Tuesday, October 28, 2008

Mocking out WCF Services in Silverlight 2.0 for Unit Testing

Brief Background:
When consuming WCF Services in Silverlight, proxy classes are generated to make using the service a lot more simple. These service proxy classes offer a simple implementation of the asynchronous service methods (synchronous service calls are not supported in silverlight).
If you're following TDD, then you want to test your client-side silverlight C# code in some sort of testing framework, and if you're writing proper unit tests, you are going to mock out the boundaries to the logic in the code (Xaml views and service references).

Problem:
Although interfaces are also generated for the service proxy classes, for some reason Microsoft left out the simple public methods in the interface definition - which 9/10 times are the only methods the developer is going to use! - go figure?!
Here is a simple service definition on the server:

image

...and here is how the svcUtil generates the proxy on the client in order to call the service methods:

Service implementation:
image

Service interface:
image

Notice that the simple "DoFooAsynch" methods have not been exposed on the interface!

Solution:
Briefly, the solution is to include the simple asynchronous helper methods in an extension of the interfaces already defined.
Do the following:

  1. Add a new class file on the Silverlight client
  2. Change the namespace to be the same as the namespace defined in the reference.cs file (where the proxy classes have be generated) - make sure to click the "Show All Files" on top of the solution explorer to find it.
  3. Define a new interface - using the example, mine would be:image  
  4. Extend the existing interface if necessary (in the example interface derives from FooBarService interface.)
  5. Include the public "[XYZ]Asynch" methods that you would like to mock into the interface as well as the return event definitions.
  6. Apply the interface to the service implementation class - luckily the class is declared as partial in the proxy, so this is quite easy: image

Now in the code, the logic to be tested should have a reference to this newly created interface, and not the actual service itself. Use either the factory pattern or dependency injection (both of which should be familiar to you if you're doing TDD) to inject the service implementation at runtime.

But what about injecting the mock during testing? Here's a pattern which I've found helpful:

image

When testing the logic code, I inject my mock service which implements the service interface into the constructor of the logic class, and in production, I let the ServiceLocator resolve the service implementation in the default constructor.

Using this methodology, you can effectively remove the service dependency in your unit tests  :) (remember to call the service implementation in your integration tests!)

Happy Testing...

Jax

3 comments:

Jeremy said...

How do you get the asynchronous behavior from the mock? The *Completed event should be raised after the *Async() call but not from with in the Async() call.

Malcolm Jack said...

Jeremy - we haven't needed to mock out the async behaviour of the service, but I would imagine it fairly simple to accomplish - in our scenario - we use Moq - so we would set up the method call with a Callback, and in the callback use a BackgroundWorker to spin off some logic, and on the completed event of the background worker, raise the completed event of the service call. Because the BackgroundWorker spins it's logic on a seperate thread, the service completed event will effectively be async.
In theory anyway ;)

Unknown said...

Thanks Jax. This post was very helpful to me.