On the Internet I found a simple calculator webservice (http://soatest.parasoft.com/calculator.wsdl). In this blogpost I will build a really simple class library which exposes the Add operation of this webservice. The purpose of this exercise is to show you how to handle this WCF dependency when unit testing the code.
Calculator 1.0 – Using the generated client
Based on the WSDL you normally create a proxy. I prefer the use of svcutil (this makes it possible to repeat the proxy generation based on command line arguments)
svcutil /serializer:DataContractSerializer /n*:ServiceProxy /out:CalculatorProxy.cs calculator.wsdl
This generated proxy will be used in the first version of the Calculator class library
using System;
using System.ServiceModel;
using ServiceProxy;
namespace CalculatorOne
{
/// <summary>
/// Implementation of a calculator which provides simple arithmetic operations
/// </summary>
public class Calculator
{
/// <summary>
/// Adds two numbers and returns the result
/// </summary>
/// <param name="numberOne"></param>
/// <param name="numberTwo"></param>
/// <returns></returns>
public float Add(float numberOne, float numberTwo)
{
float response = 0f;
var calculatorClient = new CalculatorClient();
try
{
response = calculatorClient.add(numberOne, numberTwo);
calculatorClient.Close();
}
catch (CommunicationException)
{
calculatorClient.Abort();
}
catch (TimeoutException)
{
calculatorClient.Abort();
}
catch (Exception)
{
calculatorClient.Abort();
throw;
}
return response;
}
}
}
There is quite some code for calling just a simple Add operations. Most of the code is related to exception handling to make sure that the connection is closed correctly. Don’t use the using statement to let the client proxy automatically dispose the connection, because an exception can occur within the dispose logic: http://msdn.microsoft.com/en-us/library/aa355056.aspx
Besides the huge amount of code, you are not possible to test this code without connecting to a real service. Which means that unit testing is not possible. Only integration tests against the real service are possible but you don’t want to depend on the availability of this service. When unit testing the Add operation of your library you are not interested in testing the real service. You are only interested if the dependency to the external service is called.
Time for version 2.0 of the Calculator class library which will inject the WCF client proxy to make mocking possible
Calculator 2.0 – Inject the WCF client dependency with the use of the ChannelFactory
I prefer the use of Moq (http://code.google.com/p/moq/) as a simple mocking library. Moq only supports mocking of interfaces and virtual methods of classes. The generated proxy by svcutil does not contain virtual methods so you are unable to mock this class. Besides the generated client, there is also a channel interface (ICalculatorChannel) generated. With the WCF ChannelFactory you are able to instantiate a proxy client based on this interface.
using System;
using System.ServiceModel;
using ServiceProxy;
namespace CalculatorTwo
{
/// <summary>
/// Implementation of a calculator which provides simple arithmetic operations
/// </summary>
public class Calculator
{
private readonly ICalculatorChannel calculatorClient;
public Calculator(ICalculatorChannel calculatorClient)
{
this.calculatorClient = calculatorClient;
}
/// <summary>
/// Adds two numbers and returns the result
/// </summary>
/// <param name="numberOne"></param>
/// <param name="numberTwo"></param>
/// <returns></returns>
public float Add(float numberOne, float numberTwo)
{
float response = 0f;
try
{
response = calculatorClient.add(numberOne, numberTwo);
calculatorClient.Close();
}
catch (CommunicationException)
{
calculatorClient.Abort();
}
catch (TimeoutException)
{
calculatorClient.Abort();
}
catch (Exception)
{
calculatorClient.Abort();
throw;
}
return response;
}
}
}
Now it is possible to inject a mocked client proxy when unit testing. This way you can tests if the dependency is called in the right way and you don’t depend on the availability of a real service
[TestMethod]
public void Add_WhenClientIsMocked_ShouldMockBeCalled()
{
//Arrange
var client = new Mock<ICalculatorChannel>();
client.Setup(c => c.add(It.IsAny<float>(), It.IsAny<float>())).Returns(42);
var calculator = new Calculator(client.Object);
//Act
float response = calculator.Add(30, 12);
//Assert
client.Verify(c => c.add(30, 12), Times.Once());
response.Should().BeGreaterOrEqualTo(42).And.BeLessOrEqualTo(42);
}
For assertions, I prefer the use of the FluentAssertions library (http://fluentassertions.codeplex.com/). This makes the test more readable. Above tests shows that it is possible to unit test the Add method of the Calculator class library. Still there is a lot of exception handling code and also the consumer of this class is now responsible for creating the client proxy
[TestMethod]
public void Add_When30And12IsProvidedAsInput_Should42BeReturned()
{
//Arrange
var factory = new ChannelFactory<ICalculatorChannel>("ICalculator");
var calculator = new Calculator(factory.CreateChannel());
//Act
float response = calculator.Add(30, 12);
//Assert
response.Should().BeGreaterOrEqualTo(42).And.BeLessOrEqualTo(42);
}
First let’s get rid of the close connection and exception handling code. Let’s move on to Calculator 3.0
Calculator 3.0 – Introducing a reusable client proxy
The code for closing the client proxy connection together with the exception handling code will be used for each service operation call. By introducing a client proxy this code can be removed from the method implementation
using System;
using System.ServiceModel;
namespace CalculatorThree
{
public class ClientProxy<TChannel> : IClientProxy<TChannel> where TChannel : ICommunicationObject
{
private readonly TChannel innerChannel;
public ClientProxy(TChannel innerChannel)
{
this.innerChannel = innerChannel;
}
public TResult Execute<TResult>(Func<TChannel, TResult> operation)
{
TResult result = default(TResult);
try
{
result = operation(innerChannel);
innerChannel.Close();
}
catch (CommunicationException)
{
innerChannel.Abort();
}
catch (TimeoutException)
{
innerChannel.Abort();
}
catch (Exception)
{
innerChannel.Abort();
throw;
}
return result;
}
}
}
The Execute method makes use of a Func
using ServiceProxy;
namespace CalculatorThree
{
/// <summary>
/// Implementation of a calculator which provides simple arithmetic operations
/// </summary>
public class Calculator
{
private readonly IClientProxy<ICalculatorChannel> clientProxy;
public Calculator(IClientProxy<ICalculatorChannel> clientProxy)
{
this.clientProxy = clientProxy;
}
/// <summary>
/// Adds two numbers and returns the result
/// </summary>
/// <param name="numberOne"></param>
/// <param name="numberTwo"></param>
/// <returns></returns>
public float Add(float numberOne, float numberTwo)
{
return clientProxy.Execute(c => c.add(numberOne, numberTwo));
}
}
}
The code is a lot cleaner (there is no connection closing and exception handling clutter anymore). Because the new client proxy can still be injected (IClientProxy) it is even still testable. For the unit test you are only interested if the dependency is called
[TestMethod]
public void Add_WhenClientProxyIsMocked_ShouldClientProxyBeCalled()
{
//Arrange
var clientProxy = new Mock<IClientProxy<ICalculatorChannel>>();
clientProxy.Setup(p => p.Execute(It.IsAny<Func<ICalculatorChannel, float>>())).Returns(42);
var calculator = new Calculator(clientProxy.Object);
//Act
float response = calculator.Add(30, 12);
//Assert
//it is not possible / quite difficult to check with which arguments the func was called. This has to do that Moq cannot evaluate the expression.
//therefore only the call is checked. If we want to now if the correct arguments where set, we just mock the internal proxy of the client proxy
clientProxy.Verify(c => c.Execute(It.IsAny<Func<ICalculatorChannel, float>>()), Times.Once());
response.Should().BeGreaterOrEqualTo(42).And.BeLessOrEqualTo(42);
}
When using the ClientProxy implementation it is still possible to mock the internal proxy. This way you are also able to check if the service operation is called with the correct arguments. This is not a unit test, but a unit integration tests: the calculator together with the client proxy are tested together
[TestMethod]
public void Add_WhenInnerProxyOfClientProxyIsMocked_ShouldInnerProxyBeCalledWithCorrectArguments()
{
//Arrange
var innerProxy = new Mock<ICalculatorChannel>();
innerProxy.Setup(i => i.add(It.IsAny<float>(), It.IsAny<float>())).Returns(42);
var clientProxy = new ClientProxy<ICalculatorChannel>(innerProxy.Object);
var calculator = new Calculator(clientProxy);
//Act
float response = calculator.Add(30, 12);
//Assert
innerProxy.Verify(c => c.add(30, 12), Times.Once());
response.Should().BeGreaterOrEqualTo(42).And.BeLessOrEqualTo(42);
}
Still the consumer should create the internal proxy with the use of the ChannelFactory as shown in below integration test. To simplify this, a ProxyFactory will be introduced in Calculator version 4.0
[TestMethod]
public void Add_When30And12IsProvidedAsInput_Should42BeReturned()
{
//Arrange
var factory = new ChannelFactory<ICalculatorChannel>("ICalculator");
var clientProxy = new ClientProxy<ICalculatorChannel>(factory.CreateChannel());
var calculator = new Calculator(clientProxy);
//Act
float response = calculator.Add(30, 12);
//Assert
response.Should().BeGreaterOrEqualTo(42).And.BeLessOrEqualTo(42);
}
Calculator 4.0 – Introducing a proxy factory
By introducing a proxy factory, the logic for creating a proxy with the use of the ChannelFactory can be moved to a common and reusable place.
using System.ServiceModel;
namespace CalculatorFour
{
public class WCFProxyFactory : IProxyFactory
{
#region IProxyFactory Members
public IClientProxy<TChannel> GetProxy<TChannel>(string endpointName) where TChannel : ICommunicationObject
{
var factory = new ChannelFactory<TChannel>(endpointName);
return new ClientProxy<TChannel>(factory.CreateChannel());
}
#endregion
}
}
The use of this proxy factory will change the calculator implementation a little bit
using ServiceProxy;
namespace CalculatorFour
{
/// <summary>
/// Implementation of a calculator which provides simple arithmetic operations
/// </summary>
public class Calculator
{
private readonly IProxyFactory proxyFactory;
public Calculator(IProxyFactory proxyFactory)
{
this.proxyFactory = proxyFactory;
}
/// <summary>
/// Adds two numbers and returns the result
/// </summary>
/// <param name="numberOne"></param>
/// <param name="numberTwo"></param>
/// <returns></returns>
public float Add(float numberOne, float numberTwo)
{
return proxyFactory.GetProxy<ICalculatorChannel>("ICalculator").Execute(c => c.add(numberOne, numberTwo));
}
}
}
Still unit, unit integration and integration testing is possible! The integration test also shows that using the Calculator class library is now more straightforward
//Unit test
[TestMethod]
public void Add_WhenClientProxyIsMocked_ShouldClientProxyBeCalled()
{
//Arrange
var clientProxy = new Mock<IClientProxy<ICalculatorChannel>>();
clientProxy.Setup(p => p.Execute(It.IsAny<Func<ICalculatorChannel, float>>())).Returns(42);
var proxyFactory = new Mock<IProxyFactory>();
proxyFactory.Setup(p => p.GetProxy<ICalculatorChannel>(It.IsAny<string>())).Returns(clientProxy.Object);
var calculator = new Calculator(proxyFactory.Object);
//Act
float response = calculator.Add(30, 12);
//Assert
//it is not possible / quite difficult to check with which arguments the func was called. This has to do that Moq cannot evaluate the expression.
//therefore only the call is checked. If we want to now if the correct arguments where set, we just mock the internal proxy of the client proxy
proxyFactory.Verify(p => p.GetProxy<ICalculatorChannel>("ICalculator"), Times.Once());
clientProxy.Verify(c => c.Execute(It.IsAny<Func<ICalculatorChannel, float>>()), Times.Once());
response.Should().BeGreaterOrEqualTo(42).And.BeLessOrEqualTo(42);
}
//Unit integration test
[TestMethod]
public void Add_WhenInnerProxyOfClientProxyIsMocked_ShouldInnerProxyBeCalledWithCorrectArguments()
{
//Arrange
var innerProxy = new Mock<ICalculatorChannel>();
innerProxy.Setup(i => i.add(It.IsAny<float>(), It.IsAny<float>())).Returns(42);
var clientProxy = new ClientProxy<ICalculatorChannel>(innerProxy.Object);
var proxyFactory = new Mock<IProxyFactory>();
proxyFactory.Setup(p => p.GetProxy<ICalculatorChannel>(It.IsAny<string>())).Returns(clientProxy);
var calculator = new Calculator(proxyFactory.Object);
//Act
float response = calculator.Add(30, 12);
//Assert
innerProxy.Verify(c => c.add(30, 12), Times.Once());
response.Should().BeGreaterOrEqualTo(42).And.BeLessOrEqualTo(42);
}
//Integration test
[TestMethod]
public void Add_When30And12IsProvidedAsInput_Should42BeReturned()
{
//Arrange
var factory = new WCFProxyFactory();
var calculator = new Calculator(factory);
//Act
float response = calculator.Add(30, 12);
//Assert
response.Should().BeGreaterOrEqualTo(42).And.BeLessOrEqualTo(42);
}
What’s next?
This blog post shows that it is possible to unit tests a class/method which has a dependency with a WCF Client. By introducting the additional classes, the implementation becomes clean and testable.
In the final version of the calculator the proxy factory is injected by using constructor injection. It is off course possible to resolve this dependency with an IoC (http://en.wikipedia.org/wiki/Inversion_of_control) implementation like StructureMap (http://structuremap.net/structuremap/) whereby the factory can be resolved without the use of constructor or property injection.
You can find the samples shown in the blogpost at codeplex: http://johandekoning.codeplex.com/SourceControl/changeset/view/67443#1165211


