views:

53

answers:

1

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.

A: 

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

John Simons