I am *very* keen on automating tests, so I was looking into unit testing a WCF service.
If I say "unit test", I mean a fast, in-memory, independent and automated test of a functional unit-of-work in the system.
Unit of work is at maximum one method (on my projects)
With thanks to Roy Osherove
Why should we unit test a WCF service?
- Unit tests are fast -> Quick feedback
- Unit tests are automated and repeatable -> Important for Continuous Integration
- Unit tests are independent -> No hard setup of database or service hosting on the build server
- The WCF service holds logic, like updating internal lists and sending updates to other clients
We need to make sure it works as expected now and in the future
When should we *not* unit test a WCF service?
There is one WCF service that you should not test.
The WCF service is just a wrapper around a CRUD layer, (maybe unit test your CRUD layer and not the WCF service itself)
How are we going to unit test a WCF service?
It is so easy. The WCF service implementation is just a class with some attributes.
[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple, InstanceContextMode = InstanceContextMode.Single)] [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)] public class RealTimeConnectionService : IRealTimeConnection, IDisposable { // snip snip snip }Figure: An example service
It is really easy to create an instance of this class and invoke a method on that. No problem at all.
So our unit test could look like the following:
[TestMethod] public void ConnectTest_ConnectionOk_IsSuperUser_SystemDisabled_NOTHINGSentBackToClient() { // Arrange // snip snip snip // snipped: 1. creation of fakes 2. setup of dependency injection var realTimeService = new RealTimeConnectionService(); // Act realTimeService.Connect(fakeUsercode); // Assert Assert.IsTrue(realTimeService.CurrentConnectionCount == 0) }Figure: Sample Unit test that calls "Connect" on our WCF service and verifies that the no userconnection has been added, because the system is disabled
The only problem that you are going to have, is that you are probably using the OperationContext to distinguish connections to your WCF service.
//Get usercode for this connection/session
string sessionIdFromCurrentUser = OperationContext.Current.Channel.SessionId;
Figure: Code sample that gets the sessionId from the current operation context
To get rid of that problem we mock this OperationContext with WCFMock
All you have to do is, add the following in the header of your WCF service file
namespace RealTimeConnections.ConnectionServiceService
{
using Silverlight.BaseClient.Common;
using Silverlight.CommonHelpers;
// This definition is needed to mock the OperationContext (Unit tests)
// more info about this: http://wcfmock.codeplex.com/
using OperationContext = System.ServiceModel.Web.MockedOperationContext;
// snip snip snip
Figure: Added using statement for the OperationContext (class redirect)
Now all your calls to OperationContext.Current.Channel.SessionId get intercepted by MockedOperationContext, but only in your tests you are mocking the OperationContext.
In your normal environment that MockedOperationContext acts as a proxy to the real OperationContext.
public class MockedOperationContext : IDisposable
{
[ThreadStatic]
private static IOperationContext currentContext;
public MockedOperationContext(IOperationContext context)
{
currentContext = context;
}
public static IOperationContext Current
{
get
{
if (currentContext == null)
{
return new OperationContextWrapper(OperationContext.Current);
}
return currentContext;
}
}
public void Dispose()
{
currentContext = null;
}
}
Figure: Source of MockedOperationContext
Thanks Pablo for WCFMock.
A quick intro to this you can find on Cibrax's blog
No comments:
Post a Comment