Wednesday, 28 September 2011

Hosting a Mock as a WCF service

There are a number of times where I have wanted to fire up a dummy WCF service that can be used in unit tests and be able to run some assertions against. Previously I use to write a wrapper class for my mock with the same interface and proxy all the calls to the mocked object as per the following example.

[ServiceBehaviour(InstanceContextMode = InstanceContextMode.Single)
public class MyWcfServiceMockWrapper : IMyWcfService
{
    public MyWcfServiceMockWrapper(IMyWcfService mockedService)
    {
        this.mockedService = mockedService;
    }
 
    public void SomeServiceMethod(int value)
    {
        mockedService.SomeServiceMethod(value);
    }
}

The problem with this is that you need to have a class for each WCF service you wanted to mock and proxy each method to the inner mocked object. You need to remember to decorate the class with a service behaviour setting the instance context mode to single as you are trying to start the service with an instance object.

Recently I have come up with a more reusable approach. The following code contains a static method that will generate a WCF service host based on the object that is passed into the method with a single endpoint.

public static class MockServiceHostFactory
{
    public static ServiceHost GenerateMockServiceHost<TMock>(TMock mock, Uri baseAddress, string endpointAddress)
    {
        var serviceHost = new ServiceHost(mock, new[] { baseAddress });
 
        serviceHost.Description.Behaviors.Find<ServiceDebugBehavior>().IncludeExceptionDetailInFaults = true;
        serviceHost.Description.Behaviors.Find<ServiceBehaviorAttribute>().InstanceContextMode = InstanceContextMode.Single;
 
        serviceHost.AddServiceEndpoint(typeof(TMock), new BasicHttpBinding(), endpointAddress);
 
        return serviceHost;
    }
}

The first thing that happens is a service host is created using the mock object as the service with a base address that we pass in. Next we wire up the service behaviours, the first makes sure that exceptions are returned to the client which is not necessary but can be useful. The other behaviour sets the instance context mode to single which is the same as setting it in the ServiceBehavior attribute in the previous example, this is required. Finally we create an endpoint using the address passed in a default behaviour of basic http. The factory as it stands assumes that you are only going to want one endpoint and that it should use basic http binding but this can easily be adapted to suit different requirements.

The following is an example of how you would use the factory, I will use NSubstitute but it should work fine with RhinoMocks, Moq, etc..  It is important to note that because NSubstitute as well as other mocking frameworks uses Castle to generate proxy interfaces for the mocks any attributes from the interface you are mocking will be copied to the proxy interface it generates. Because of this when the service host is created WCF will complain. To resolve this you need to tell Castle not to copy the ServiceContract attribute, this must be done before you generate your service mock.

Castle.DynamicProxy.Generators.AttributesToAvoidReplicating.Add<ServiceContractAttribute>();
 
var myWcfServiceMock = Substitute.For<IMyWcfService>();
var mockServiceHost = MockServiceHostFactory.GenerateMockServiceHost(myWcfServiceMock , new Uri("http://localhost:8001"), "MyService");
mockServiceHost.Open();
...
mockServiceHost.Close();

Happy mocking.

5 comments:

  1. Modifying the InstanceContextMode and the Castle trick were just the things I was looking for.

    Nice tip!

    ReplyDelete
  2. Hello, I've been trying all day to make this work and I'm kinda desperate at the moment I think I've done pretty much what you explained in order to test a signalR hub in an asp.NET project that has a wcf service client but I get the following error :
    Cannot have two operations in the same contract with the same name, methods ClientConnectAsync and ClientConnect in type ReflectorLike.ChatReference.IChatService violate this rule.
    I also asked my question on http://stackoverflow.com/questions/30369544/auto-generated-async-methods-violate-wcf-service-rule

    ReplyDelete
  3. You can definitely see your expertise in the paintings you write. The world hopes for even more passionate writers such as you who aren’t afraid to say how they believe. Always go after your heart https://onohosting.com/

    ReplyDelete
  4. The private-label is the best type of reseller plan because it allows you to retain full control over your customer's websites. cheap web hosting in bangladesh



    ReplyDelete