Unit Testing WCF Services
I've seen a lot of people test WCF services using integration tests. You know, where you create a small program as a test harness that creates a client for a web service, calls the service and checks what happened. Similarly when you want to test your client side code is using the service properly then you have to have your client talking to something, so you need to have a test service running and that can be a pain at times, especially if the service is hosted somewhere in the cloud.
Testing a WCF Service
Testing WCF services themselves is actually quite straightforward. Since a WCF service library is really just a normal class library it means that WCF services can can actually be called and tested using NUnit, MSTest or your favourite xUnit framework without needing a proper WCF client at all as I'll show you here:
Let's start by adding a WCF Service to a service library:
When we do, we get two new files added to our project - MyService.cs and IMyService.cs.
MyService.cs is just a simple skeleton as shown here:
namespace WcfServiceLibrary1
{
public class MyService : IMyService
{
public void DoWork()
{
}
}
}
The interface likewise is also very simple:
namespace WcfServiceLibrary1
{
[ServiceContract]
public interface IMyService
{
[OperationContract]
void DoWork();
}
}
Nothing to it. So let's implement something simple so that we at least have something to test :-) How about we change DoWork() to return an int with the current hour of the day and update the interface definition to match. Something like this:
public int DoWork()
{
return DateTime.Now.Hour;
}
Now, being good programmers, we want to make sure our incredibly complex method works as expected so let's write a test for it. Remembering that the MyService class is just a normal class we don't actually need to do anything via WCF at all. Just test it like so:
[TestMethod()]
public void DoWorkTest()
{
MyService target = new MyService();
int expected = DateTime.Now.Hour;
Assert.AreEqual(expected, target.DoWork());
}
I know the example is a little too simplistic, but you should get the idea.
Testing a WCF Client
So now that we have a working service how do call it? And how do we test our client? Now when we add a WCF service reference in our client project Visual Studio will generate the code for a WCF service client - it's this service client that our application will use, so is there any value in testing the client generated by Visual Studio itself? Probably not. So the question then becomes: how do we test that the WCF service client is being used correctly by our application code.
Let's start an example by adding a service reference to our WCF Service we created above, similar to what's shown here. This is what we'll use in our client application.
Visual Studio goes ahead and adds the reference to the solution and behind the scenes creates a MyServiceClient class that we can then call from our application as shown in the following code:
public string CallMyServiceClient()
{
int result;
MyServiceClient client = new MyServiceClient();
result = client.DoWork();
return result.ToString();
}
Code like the above is something you will see in many places around the web, however we have just made life a lot harder for ourselves than we need to. Can you see the problem? If I want to test the CallMyServiceClient method I have to instantiate a WCF client and call it, which also means I also have to have a WCF service running and ensure all my WCF end points are configured correctly for the test environment. It's OK when it's a simple like this, but in a large application with many services and people involved this sort of thing can get out of hand very quickly.
Further, if I wanted some way to see what happens to my code should the service throw an exception I'd have some difficulties so my error handling code (or lack thereof) will usually go largely untested.
Thankfully there are a few simple changes we can make to make this testability problem go away.
First, have a look at the declaration of the MyServiceClient and you'll see that Visual Studio has generated something like this:
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
public partial class MyServiceClient :
System.ServiceModel.ClientBase<WCFClientLibrary1.MyServiceReference.IMyService>
, WCFClientLibrary1.MyServiceReference.IMyService {
public MyServiceClient() {
}
The interesting thing to note here is that MyServiceClient is implementing the IMyService interface. So if we wanted we could remove the concrete class reference and use the interface like so:
public string CallMyServiceClient()
{
int result;
IMyService client = new MyServiceClient();
result = client.DoWork();
return result.ToString();
}
But this doesn't help much since we still have that instantiation of the MyServiceClient in our method to deal with. We need to get that out of there. To do that we'll use Dependency Injection - a technique where instead of the class creating the dependencies it needs, we pass into the class everything else that the class has a dependency on - in this case the MyServiceClient class. Here's how we could do it:
public class MyClass
{
private IMyService client;
public MyClass(IMyService wcfClient)
{
client = wcfClient;
}
public string CallMyServiceClient()
{
int result = client.DoWork();
return result.ToString();
}
So now when we create an instance of MyClass we pass in an instance of the MyServiceClient class so that MyClass doesn't have to create a reference to MyServiceClient. We could do this either through our own application code higher up the call stack or through the use of an Inversion of Control container such as Unity, Castle Windsor or any of the other choices out there.
Now that we've introduced dependency injection we have also given ourselves a way to test MyClass without actually hitting the WCF service client at all.
What we need to do is to create a fake version of the MyServiceClient class that we can use as a substitute for the real WCF service client and pass that to MyClass instead. We could, if we chose, create this fake class ourselves, but mocking frameworks exist to make our life easier in the regard and come with a bunch of extra features that let us do things such as setting return values when calls are made, without us having to write that ourselves.
Here's a test we might use with our client using the Rhino Mocks framework:
[TestMethod()]
public void ClientTest()
{
IMyService mock = MockRepository.GenerateMock<IMyService>();
mock.Expect(t => t.DoWork()).Return(10);
MyClass classUnderTest = new MyClass(mock);
Assert.AreEqual("10", classUnderTest.CallMyServiceClient());
mock.VerifyAllExpectations();
}
Let's have a look at this test in a little more detail. What are we doing here?
- We're creating a fake version of the IMyService class called "mock".
- We then tell the mock object to return the value 10 when its DoWork method is called.
- Next we create a MyClass instance and pass the fake class through to it in place of a real WCF service client.
- Then we call our classUnderTest and assert that the method returned the expected value
- And on the last line we also check that the DoWork() method was called on our mock object (i.e. we didn't just return from MyClass without calling the IMyService method)
This is quite useful as we now have a way to test our application code is making the appropriate calls to the WCF client without needing to actually spin up a full WCF client & service nor do we have to do any testing across the wire. This example is also simple enough to extend so that when the DoWork() method is called we can throw a WCF exception instead to test how well our class handles failures.
I hope this helps you improve your testing with WCF in the future. Good luck!