Including exception details when using a Castle WCF Facility hosted service - c#

I'm having some trouble unit testing a bit of code while utilising the Wcf Facility for Castle Windsor. It seems to refuse to include Exception Details when an Exception is thrown, I only get to see empty FaultExceptions. This is my test setup:
First, here's a stub of the service that I will be connecting to:
[ServiceBehavior(IncludeExceptionDetailInFaults = true)]
public abstract class StubAilDataService : IAilDataService
{
public virtual Method1()
{
}
/* More methods */
}
Notice that I've specified IncludeExceptionDetailsInFaults and set it to true.
This is how I host the stubbed service:
private ServiceHost _host;
private StubAilDataService _rhinoService;
[TestFixtureSetUp]
public void FixtureSetup()
{
var sba = new ServiceDebugBehavior {IncludeExceptionDetailInFaults = true};
_rhinoService = MockRepository.GeneratePartialMock<StubAilDataService>();
_host = new ServiceHost(_rhinoService);
_host.AddServiceEndpoint(typeof(IAilDataService), new WSHttpBinding("wsSecure"), "http://localhost:8080/Service");
_host.Open();
_container.AddFacility<WcfFacility>().Register(
Component.For<IServiceBehavior>().Instance(sba),
Component.For<IAilDataService>()
.LifeStyle.PerWcfSession()
.ActAs(new DefaultClientModel
{
Endpoint =
WcfEndpoint.BoundTo(new WSHttpBinding("wsSecure"))
.At("http://localhost:8080/Service")
}) // More stuff
);
}
I've done a PartialMock in an attempt to keep the Include.. attribute on the mocked object.
And the test. Notice that I tell my mocked service to throw a very specific exception here.
[Test]
[ExpectedException(typeof(AggregateException))]
public void AnalyzeProductCreationJobs_Should_Throw_Aggregate_Exception_If_A_DataService_Call_Throws()
{
//Arrange
_rhinoService.Expect(
s => s.CategoryIsInAgility(Arg<string>.Matches(str => str.Equals("000103")), Arg<Settings>.Is.Anything))
.Throw(new FaultException<InvalidOperationException>(new InvalidOperationException("FAIL!")));
var product = new Product { CategoryCode = "000103" };
var analyzer = TypeResolver.Resolve<ProductAnalyzer>();
//Act
analyzer.AnalyzeProductCreationJobs(product);
}
And finally, the code I'm actually testing:
public class ProductAnalyzer
{
private readonly IDataServiceClient _dataClient;
public ProductAnalyzer(IDataServiceClient dataClient)
{
_dataClient = dataClient;
}
public IEnumerable<IAdsmlJob<CreateResponse>> AnalyzeProductCreationJobs(Product product)
{
IList<IAdsmlJob<CreateResponse>> creationJobs = new List<IAdsmlJob<CreateResponse>>();
var task = Task.Factory.StartNew(() =>
{
// This is where the exception set up in my .Expect gets thrown.
bool categoryIsInAgility = _dataClient.CategoryIsInAgility(product.CategoryCode);
// Logic
}); // Continued by more tasks
try
{ task.Wait(); }
catch (AggregateException ae)
{
ae.Flatten().Handle(ex => ex is TaskCanceledException);
}
}
I would expect the service to crash and throw the exception I've set it up to throw - but the Wcf Facility seems to strip away the exception that is thrown and replace it with an empty FaultException instead.
Am i missing something? There are quite a few components working together here - and I'm not 100% sure where things go wrong.

You have to explicitly declare the type of fault exception the method throws on the interface.
Example:
[ServiceContract(Namespace = "http://www.example.com")]
public interface IAilDataService
{
[OperationContract]
[FaultContract(typeof(OperationPermissionFault))]
[FaultContract(typeof(InvalidOperationException))]
void Method1();
}
See http://msdn.microsoft.com/en-us/library/system.servicemodel.faultcontractattribute.aspx

Related

Moq.MockException: Invocation failed with mock behavior Strict

In the below code, I'm using Moq to test if my Post method is returning CreatedAtRoute StatusCode on successfully addind a book but the test case is failing in Act part when it calls the service and shows the following error:
Moq.MockException: 'IEventRepository.AddEvent(TEMS.Business.Entities.Event) invocation failed with mock behavior Strict.
All invocations on the mock must have a corresponding setup.'
Test Setup and Tear Down:
private Mock<IBookRepository> mockBookRepository;
public override void TestSetup()
{
mockBookRepository = this.CreateAndInjectMock<IBookRepository>();
Target = new BooksController(mockBookRepository.Object);
}
public override void TestTearDown()
{
mockBookRepository.VerifyAll();
}
TestCase:
[Fact]
public void AddBook_ReturnCreatedAtRoute()
{
// to prevent autofixture throwing ThrowingRecursionBehavior
var fixture = new Fixture();
fixture.Behaviors
.OfType<ThrowingRecursionBehavior>()
.ToList()
.ForEach(b => fixture.Behaviors.Remove(b));
fixture.Behaviors.Add(new OmitOnRecursionBehavior(1));
var books = fixture.Create<Book>();
this.mockBookRepository.Setup(s => s.AddBook(books)).Returns(1);
// Act
BookInputModel booksViewModel = convertDbModelToInputModel(books);
var actual = Target.Post(booksViewModel);
// Assert
var actionResult = Assert.IsType<ObjectResult>(actual);
Assert.Equal((int)HttpStatusCode.Created, actionResult.StatusCode);
this.mockBookRepository.Verify(v => v.AddBook(books), Times.Once);
}
Post Method:
public ActionResult Post(BookInputModel request)
{
try
{
Book addBooks = convertDbModelToInputViewModel(request);
var result = _service.AddBook(addBooks);
if (result == 0) return BadRequest();
return CreatedAtRoute("GetBook", new { id = addBooks.Id }, request);
}
catch (Exception ex)
{
return StatusCode(500, ex.Message);
}
}
Repository:
public int AddBook(Book request)
{
Book newBook = new Book()
{
Name = request.Name,
Author = request.Author,
Publication = request.Publication,
TotalPages = request.TotalPages,
};
if (newBook == null) return 0;
else
{
_context.Book.Add(newBook);
_context.SaveChanges();
return 1;
}
}
Took me a while to realise this little error that was causing the problem - the problem was happening in Act part for the very valid reason as I'm doing setup using DbModel and in Act I'm passing ViewModel(as the Post method in controller requires it) which raises the conflict. Now as far as I'm aware of, the only way to resolve it by using the same model in Post method as of Repository.

"No connection string named 'Entities' could be found in the application config file." error with Moq

I'm using Moq to provide a mocking context for my Oracle db. But when I call _context.Entry with the mocked context, I get an InvalidOperationException.
"No connection string named 'Entities' could be found in the application config file."
I'm already providing a mocked context, so not sure why it's still trying to read connection string to create the context.
// generated code for oracle db
public partial class Entities : DbContext
{
public Entities()
: base("name=Entities")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
throw new UnintentionalCodeFirstException();
}
public virtual DbSet<ACTIVITY_CODE> ACTIVITY_CODE { get; set; }
}
// my code
public partial class Entities : System.Data.Entity.DbContext
{
public Entities(string scon) : base(scon) { }
}
// my code
public partial class ActivityCodeService
{
private Entities _context;
public ActivityCodeService(Entities context)
{
this._context = context;
}
public ACTIVITY_CODE Update(ACTIVITY_CODE item)
{
ACTIVITY_CODE ret = null;
var found = Read(item.ACT_ID);
if (found != null)
{
_context.Entry<ACTIVITY_CODE>(found).CurrentValues.SetValues(item); // throws InvalidOperationException "No connection string named 'Entities' could be found in the application config file."
_context.SaveChanges();
ret = item;
}
return ret;
}
}
// test code
[TestMethod]
public void activity_code_update_test()
{
// arrange
var mockSet = new Mock<DbSet<ACTIVITY_CODE>>();
mockSet.As<IQueryable<ACTIVITY_CODE>>().Setup(o => o.Provider).Returns(testData.Provider);
mockSet.As<IQueryable<ACTIVITY_CODE>>().Setup(o => o.Expression).Returns(testData.Expression);
mockSet.As<IQueryable<ACTIVITY_CODE>>().Setup(o => o.ElementType).Returns(testData.ElementType);
mockSet.As<IQueryable<ACTIVITY_CODE>>().Setup(o => o.GetEnumerator()).Returns(testData.GetEnumerator());
var mockContext = new Mock<Entities>();
mockContext.Setup(c => c.ACTIVITY_CODE).Returns(mockSet.Object);
var expected = new ACTIVITY_CODE() { ACT_ID = 1, ACT_CODE = "code 2", ACT_DESC = "desc 2" };
var target = new ActivityCodeService(mockContext.Object);
// act
target.Update(expected);
}
But if I don't use _context.Entry, then the test runs fine which is expected. So does that mean _context.Entry is creating another internal context and ignoring my mocked context?
// my code
public ACTIVITY_CODE Update(ACTIVITY_CODE item)
{
var ret = _context.ACTIVITY_CODE.FirstOrDefault(o => o.ACT_ID == item.ACT_ID);
if (ret != null)
{
ret.ACT_CODE = item.ACT_CODE;
ret.ACT_DESC = item.ACT_DESC;
_context.SaveChanges(); // this will work fine with Moq's mocked context
}
return ret;
}
Entry isn't, and can't be, mocked by Moq as it's not virtual so it is still going to try to use the database that it believes is there. That's why it's looking for a connection string.
What I have been able to do which has worked well is to abstract that function call into a virtual method that I had enough control over to actually mock.
Alternatives:
There are some tools based on answers to other questions that have the same base problem. Looks like TypeMock and JustMock may be able to work around the issue.
Additionally, it looks like MS Fakes should be able to shim it. After a little investigation it looks like it'd work something like this:
ShimDbEntityEntry<TestModel> entryMock = new ShimDbEntityEntry<TestModel>();
ShimDbPropertyValues mockValues = new ShimDbPropertyValues();
mockValues.SetValuesObject = (newValues) => { }; // Manually do something here
entryMock.CurrentValuesGet = () => mockValues;
ShimDbContext.AllInstances.EntryOf1M0<TestModel>((ctx, target) => entryMock);

Unit test that legacy code reacts to ThreadAbortException in a certain way

I've got an existing bit of legacy code that I want to get under test. Here's a repro of the essentials:
public class LegacyUnit
{
private readonly ICollaborator collaborator;
public LegacyUnit(ICollaborator collaborator)
{
this.collaborator = collaborator;
}
public object GetStuff(HttpContextBase context, string input)
{
try
{
if (input == "")
{
context.Response.End();
}
collaborator.DoOtherStuff();
return "Done!";
}
catch (ThreadAbortException)
{ }
return null;
}
}
Now, this legacy unit has some issues, but for now I'm just trying to get it under test. Specifically, I want to test that collaborator.DoOtherStuff is not called if Response.End() raised a ThreadAbort.
The problem: how do you raise such an exception?
I've read through this question and its answers on ThreadAbortException, and understand that it's special. However, I don't see from those posts how to handle this in unit tests.
Here's my attempt:
[Test]
public void DoesNotCallCollaboratorOnThreadAbort()
{
var testResponseMock = new Mock<HttpResponseBase>();
var testContextMock = new Mock<HttpContextBase>();
var collaboratorMock = new Mock<ICollaborator>();
testContextMock.Setup(x => x.Response).Returns(testResponseMock.Object);
testResponseMock.Setup(x => x.End()).Throws<ThreadAbortException>(); // Compile error
var unit = new LegacyUnit(collaboratorMock.Object);
unit.GetStuff(testContextMock.Object, "");
collaboratorMock.Verify(c => c.DoOtherStuff(), Times.Never);
}
Obviously the compiler complains: ThreadAbortException has no available constructor. Also, it's sealed (probably for good reasons), so creating a "testable" sub-class won't work.
What is the proper way to get such code under test? Is it even feasible, or is the LegacyUnit just too test-unfriendly?
Full, minimal repro (empty .NET 4.5 class library with NUnit 2.6.4 and Moq 4.5.9):
public interface ICollaborator
{
void DoOtherStuff();
}
public class LegacyUnit
{
private readonly ICollaborator collaborator;
public LegacyUnit(ICollaborator collaborator)
{
this.collaborator = collaborator;
}
public object GetStuff(HttpContextBase context, string input)
{
try
{
if (input == "") context.Response.End();
collaborator.DoOtherStuff();
return "Done!";
}
catch (ThreadAbortException)
{ }
return null;
}
}
[TestFixture]
public class LegacyUnitTests
{
[Test]
public void DoesNotCallCollaboratorOnThreadAbort()
{
var testResponseMock = new Mock<HttpResponseBase>();
var testContextMock = new Mock<HttpContextBase>();
var collaboratorMock = new Mock<ICollaborator>();
testContextMock.Setup(x => x.Response).Returns(testResponseMock.Object);
testResponseMock.Setup(x => x.End()).Throws<ThreadAbortException>(); // Compile error here
var unit = new LegacyUnit(collaboratorMock.Object);
unit.GetStuff(testContextMock.Object, "");
collaboratorMock.Verify(c => c.DoOtherStuff(), Times.Never);
}
}
ThreadAbortException is raised in the target thread by calling Abort on it. You can create a thread to run the test and call Abort in your mock of testResponseMock.End e.g.
testContextMock.Setup(x => x.Response).Returns(testResponseMock.Object);
var unit = new LegacyUnit(collaboratorMock.Object);
var thread = new Thread(() => unit.GetStuff(testContextMock.Object, ""));
testResponseMock.Setup(x => x.End()).Callback(() => { Thread.CurrentThread.Abort(); });
thread.Start();
thread.Join();
collaboratorMock.Verify(c => c.DoOtherStuff(), Times.Never);

Bug in Autofac MEF integration: Instantiates component when only querying for metadata

There appears to be a bug in how Autofac handles service instantiation when integrating with MEF
The following test show that MEF does not instantiate the services before it have to. (In this case, I'm only querying for metadata)
[TestMethod]
public void Mef_DoesNotInstantiateService_WhenOnlyQueryingForMetadata()
{
var aggregateCatalog = CreateMefCatalog();
var container = new CompositionContainer(aggregateCatalog, true);
var serviceConsumer = container.GetExportedValue<ServiceConsumer>();
serviceConsumer.Services.Any(x => x.Metadata.Name == "Service1").Should().BeTrue();
}
The following test is failing, since Autfac is trying to create an instance of Service1 - which throws an exception in the constructor.
[TestMethod]
public void Autofac_DoesNotInstantiateService_WhenOnlyQueryingForMetadata()
{
var aggregateCatalog = CreateMefCatalog();
var builder = new ContainerBuilder();
builder.RegisterComposablePartCatalog(aggregateCatalog);
var container = builder.Build();
//Next line will throw an exception. (Autofac is instantiating the service, but should not)
var serviceConsumer = container.Resolve<ServiceConsumer>();
//Note: This test will never get here..
serviceConsumer.Services.Any(x => x.Metadata.Name == "Service1").Should().BeTrue();
}
Other code required by the tests
static AggregateCatalog CreateMefCatalog()
{
return new AggregateCatalog(new List<ComposablePartCatalog>
{
new AssemblyCatalog(Assembly.GetExecutingAssembly())
});
}
[Export]
class ServiceConsumer
{
[ImportMany]
public IEnumerable<Lazy<IService, INameMetadata>> Services { get; set; }
}
public interface IService { }
[Export(typeof (IService))]
[ExportMetadata("Name", "Service1")]
public class Service1 : IService
{
public Service1()
{
throw new Exception("This service should never be created");
}
}
public interface INameMetadata
{
string Name { get; }
}
BTW: I'm using the currently stable versions: Autofac 3.5.2 and Autofac.Mef 3.0.3

Are these Singleton Unit Tests actually working as expected?

I have a bootstrapper object that I'm trying to test (using xunit). The tests appear to pass, but I'm seeing some weird things in one of the test runners I use (ncrunch). I use both ncrunch and the resharper xunit runner. My idea was to take the assembly that the singleton is in, load it into a new appdomain, run my tests using reflection, then unload the app domain. As I said, the tests pass in both ncrunch and resharper, but ncrunch is not showing the execution paths that I expect. Here's the code:
public class Bootstrapper
{
private static Bootstrapper booted;
public Bootstrapper()
{
// performs boot tasks
}
public static void Boot()
{
if (booted == null)
{
var staticboot = new Bootstrapper();
Booted = staticboot;
}
}
public static Bootstrapper Booted
{
get
{
if (booted == null) throw new InvalidOperationException("Should call Boot() before accessing the booted object");
return booted;
}
set { booted = value; }
}
}
public class Tests
{
[Fact]
public void TryingToAccessBootedKernelBeforeBootThrowsException()
{
var setup = this.SetupTestingDomainWithAssembly("StackOverflowQuestion.Tests.dll");
var kernelType = setup.Item2.GetType("StackOverflowQuestion.Tests.Bootstrapper");
var bootedkernelProperty = kernelType.GetProperty("Booted");
try
{
bootedkernelProperty.GetValue(null);
}
catch (Exception e)
{
Assert.IsType(typeof(InvalidOperationException), e.InnerException);
}
AppDomain.Unload(setup.Item1);
}
[Fact]
public void CanAccessKernelAfterBooting()
{
var setup = this.SetupTestingDomainWithAssembly("StackOverflowQuestion.Tests.dll");
var kernelType = setup.Item2.GetType("StackOverflowQuestion.Tests.Bootstrapper");
var bootMethod = kernelType.GetMethod("Boot");
bootMethod.Invoke(null, new object[] { });
var bootedkernelProperty = kernelType.GetProperty("Booted");
Assert.DoesNotThrow(() => bootedkernelProperty.GetValue(null));
AppDomain.Unload(setup.Item1);
}
[Fact]
public void BootIsIdempotent()
{
var setup = this.SetupTestingDomainWithAssembly("StackOverflowQuestion.Tests.dll");
var kernelType = setup.Item2.GetType("StackOverflowQuestion.Tests.Bootstrapper");
var bootMethod = kernelType.GetMethod("Boot");
bootMethod.Invoke(null, new object[] {});
var bootedkernelProperty = kernelType.GetProperty("Booted");
var bootedKernel = (Bootstrapper)bootedkernelProperty.GetValue(null);
bootMethod.Invoke(null, new object[] {});
var secondCall = (Bootstrapper)bootedkernelProperty.GetValue(null);
Assert.Equal(bootedKernel, secondCall);
AppDomain.Unload(setup.Item1);
}
private Tuple<AppDomain, Assembly> SetupTestingDomainWithAssembly(string assemblyPath)
{
// we guarantee that each domain will have a unique name.
AppDomain testingDomain = AppDomain.CreateDomain(DateTime.Now.Ticks.ToString());
var pancakesAssemblyName = new AssemblyName();
pancakesAssemblyName.CodeBase = assemblyPath;
var assembly = testingDomain.Load(pancakesAssemblyName);
return new Tuple<AppDomain, Assembly>(testingDomain, assembly);
}
}
Now, I recognize that there is some cleanup that needs to happen code-wise, but I was happy to see them all green. If I fiddle with them to make them fail, that works as expected. The only thing that's kind of smelly is that ncrunch is reporting weird execution paths. Specifically, ncrunch is showing that the line that throws the invalid operation exception is never executed.
I suppose it's possible that ncrunch has a bug when dealing with other application domains, but it's more likely that I don't actually understand what's going on with the app domains, but I'm not sure where to continue from here.
Also, I do know that singletons are bad, but I believe bootstrappers are one place where they actually are useful. You want to guarantee that they are only booted once.
Unless I'm missing something here.. it doesn't look like you are actually invoking anything in your other app domain. Your reflection is occurring in the current app domain. Take a look at the DoCallback method: http://msdn.microsoft.com/en-us/library/system.appdomain.docallback.aspx
public class Tests
{
[Fact]
public void TryingToAccessBootedKernelBeforeBootThrowsException()
{
var appDomain = AppDomain.Create(Guid.NewGuid());
try
{
appDomain.DoCallBack(new CrossAppDomainDelegate(TryingToAccessBootedKernelBeforeBootThrowsException_AppDomainCallback));
}
catch (Exception e)
{
Assert.IsType(typeof(InvalidOperationException), e.InnerException);
}
AppDomain.Unload(appDomain);
}
public static void TryingToAccessBootedKernelBeforeBootThrowsException_AppDomainCallback()
{
var bootstrapper = BootStrapper.Booted;
}
}

Categories