Mocking WCF Services Using Moq

Learn how to mock WCF services using Moq, an easy to use mocking library for .NET.

Introduction

Unit testing means testing the smallest possible code that can be tested (unit). In the .NET Framework, a unit would be equivalent to a method or property. If a method calls a service, we don’t want the method to know the exact type of service that it will use because that will make the code tightly-coupled with a specific service implementation. To have a decoupled code, we use design patterns based on inversion of control like dependency injection and service locator.

In our unit tests, we can inject or provide mock implementations of the services the method needs. For this purpose, we can use a mocking library. There are several mocking libraries or frameworks like Rhino Mocks, TypeMock, NMock, etc. I was looking for a mocking library that is easy to understand so that learning it won’t take up much of my time. I saw Moq and found the syntax intuitive so I gave it a try. You can learn more about Moq at http://code.google.com/p/moq/. To demonstrate how to use Moq (at least the basics), I decided to mock WCF services.

Getting Started

Let’s start with a basic example: a client application calls a WCF service and waits for the return value. The following code listing shows the service and data contracts that define the service.

[ServiceContract]
public interface IOrderService
{
[OperationContract]
Order GetOrder(int orderId);
}

[DataContract]
public class Order
{
[DataMember]
public int Id { get; set; }
}

Listing 1. Example WCF Service and Data Contracts

In our client application, we have a class that consumes the WCF service. This class takes in an IOrderService interface as a parameter to its constructor so that we can inject a mock object in our unit tests.

public class OrderClient
{
private readonly IOrderService orderService;

public OrderClient(IOrderService orderService)
{
this.orderService = orderService;
}

public Order GetOrder(int orderId)
{
return orderService.GetOrder(orderId);
}
}

Listing 2. WCF Service Consumer

The OrderClient class has a GetOrder method, which just calls the service operation having the same signature. We will be testing this method for the next several unit tests. The following code listing shows a simple test using NUnit. I’ll be using NUnit for all the tests in this article.

[TestFixture]
public class OrderClientTests1
{
[Test]
public void GetOrderTest()
{
var serviceClient = new OrderServiceClient();
var client = new OrderClient(serviceClient);
Order order = client.GetOrder(1);
Assert.AreEqual(order.Id, 1);
}
}

Listing 3. GetOrders Unit Test

The OrderServiceClient is the proxy for the WCF service. I manually coded it instead of using the Add Service Reference feature of Visual Studio to avoid clutter.

public class OrderServiceClient : ClientBase<IOrderService>, IOrderService
{
public Order GetOrder(int orderId)
{
return Channel.GetOrder(orderId);
}
}

Listing 4. OrderService Proxy

Using this class requires us to have the WCF service up and running since it will create a channel. We also need to provide the necessary configuration settings like the endpoint address, binding and contract. Since our unit test does not create a service host and include the needed settings, we encounter the following exception:

System.InvalidOperationException : Could not find default endpoint element that references contract 'MockWCFServicesMoqDemo.IOrderService' in the ServiceModel client configuration section. This might be because no configuration file was found for your application, or because no endpoint element matching this contract could be found in the client element.

We could add the configuration settings and run the WCF service to make our test work but then that would be more of an integration test. Instead of using a proxy, we could use a mock object.

Some Moq Basics

Let’s try to change the unit test, this time using Moq to mock the service. To use Moq, we have to download the binaries at http://code.google.com/p/moq/downloads/list and add a reference to the assembly. The following code listing shows the updated unit test code.

[TestFixture]
public class OrderClientTests2
{
Mock<IOrderService> orderService;

[SetUp]
public void Setup()
{
orderService = new Mock<IOrderService>();
}

[Test]
public void GetOrderTest()
{
var client = new OrderClient(orderService.Object);
Order order = client.GetOrder(1);
Assert.AreEqual(order.Id, 1);
}
}

Listing 5. Mocking a Synchronous WCF Service

The Mock(Of T) generic class is defined in the Moq assembly. In our example, the Mock<IOrderService> object provides us a mock implementation of the IOrderService interface. We can’t pass the object directly into the OrderClient constructor since it requires an IOrderService parameter, not Mock<IOrderService>. We can get the actual IOrderService object via the Object property. Currently, the assertion in the test method will fail because the return value of the mock’s GetOrder method is null. That is because we still haven’t specified what should be returned when the GetOrder method is called. By default, Moq will return default values like null or zero, depending on the data type. We can change this behavior by adding setups.

[TestFixture]
public class OrderClientTests3
{
Mock<IOrderService> orderService;

[SetUp]
public void Setup()
{
orderService = new Mock<IOrderService>(MockBehavior.Strict);
orderService
.Setup<Order>(o => o.GetOrder(1))
.Returns(new Order { Id = 1 });
}

[Test]
public void GetOrderTest()
{
var client = new OrderClient(orderService.Object);
Order order = client.GetOrder(1);
Assert.AreEqual(order.Id, 1);

orderService.Verify<Order>(o => o.GetOrder(1), Times.Once());
}
}

Listing 6. Using Setup and Verify

If we put in words the code that we added in the Setup method, it means that when the GetOrder method is called on the mock and the passed parameter is 1, return an object of type Order where its Id property is set to 1. This time, the assertion will pass. We can also verify whether a mock’s method is called exactly once, never, twice, etc. In our example, we would like to check if it is called only once. What if we changed the GetOrder’s parameter from 1 to 2? Moq will now throw the following exception because we constructed the mock with the MockBehavior.Strict parameter.

Moq.MockException : IOrderService.GetOrder(2) invocation failed with mock behavior Strict. All invocations on the mock must have a corresponding setup.

If we want the mock to accept another parameter value, then we have to add another setup or change the existing one to allow other values.

[TestFixture]
public class OrderClientTests4
{
Mock<IOrderService> orderService;

[SetUp]
public void Setup()
{
orderService = new Mock<IOrderService>(MockBehavior.Strict);
orderService
.Setup<Order>(o => o.GetOrder(It.IsAny<int>()))
.Returns((int orderId) => new Order { Id = orderId });
}

[Test]
public void GetOrderTest()
{
var client = new OrderClient(orderService.Object);
Order order = client.GetOrder(1);
Assert.AreEqual(order.Id, 1);
Order order2 = client.GetOrder(2);
Assert.AreEqual(order2.Id, 2);

orderService.Verify<Order>(o => o.GetOrder(It.IsAny<int>()), Times.Exactly(2));
}
}

Listing 7. Using the It.IsAny Method and Setting the Return Value

We have updated the unit test code so that the GetOrder method accepts any integer. This is achieved by using the It.IsAny method. We can also use a lambda expression in the Returns method so that we can access the integer passed to the GetOrder method. Now, the mock’s GetOrder method accepts any integer and returns an Order where its Id property is set to the integer.

Throwing Exceptions

As we know, exceptions caused by timeouts, faulted channels, etc. are sometimes thrown when we try to invoke WCF services. Usually, we have proper exception handling code in our client applications and we also want to test that. Fortunately, we can also let our mocks throw exceptions. Let’s change our unit test code so that the GetOrder method throws an exception when the passed integer is greater than 10.

[TestFixture]
public class OrderClientTests5
{
Mock<IOrderService> orderService;

[SetUp]
public void Setup()
{
orderService = new Mock<IOrderService>(MockBehavior.Strict);
orderService
.Setup<Order>(o => o.GetOrder(It.Is<int>(i => i <= 10)))
.Returns((int orderId) => new Order { Id = orderId });
orderService
.Setup<Order>(o => o.GetOrder(It.Is<int>(i => i > 10)))
.Throws(new Exception("Some Exception"));
}

[Test]
public void GetOrderTest()
{
var client = new OrderClient(orderService.Object);
Order order = client.GetOrder(1);
Assert.AreEqual(order.Id, 1);
Order order2 = client.GetOrder(2);
Assert.AreEqual(order2.Id, 2);

Assert.Throws<Exception>(() => client.GetOrder(11));

orderService.Verify<Order>(o => o.GetOrder(It.IsAny<int>()), Times.Exactly(3));
}
}

Listing 7. Using the It.Is Method and Throwing an Exception

Using the It.Is method, we can specify certain conditions and the corresponding actions to be taken when a condition is met. In our example, there are two conditions: the integer is less than or equal to 10, and the integer is greater than 10. Using the Throws method, we can tell the mock to throw an exception when the second condition is met. Since the code we are testing does not handle any exception, the exception will bubble up to our unit test code. We can simply assert that the method throws an exception. We can also throw other types of exceptions in our tests so that the appropriate exception handling codes are all covered.

Mocking Asynchronous WCF Services

It is common to see asynchronous WCF services since some services take some time to execute. These services could be getting large data from a database or performing some extensive file input/output operations. Since control is handed immediately back to the client application, the client application just waits for a callback method to be invoked by the service when it has completed the operation. By then, the client application can obtain the output of the operation. We can also let our mock service mimic this behavior by using the Callback method, as you will see later. First, let’s create an asynchronous OrderService.

[ServiceContract(Name = "IOrderService")]
public interface IAsyncOrderService
{
[OperationContract(AsyncPattern = true)]
IAsyncResult BeginGetOrder(int orderId, AsyncCallback callback, object asyncState);

Order EndGetOrder(IAsyncResult result);
}

Listing 8. Asynchronous Order Service

Same thing we did with the IOrderService, we will create the corresponding WCF service consumer class which we will be testing.

public class AsyncOrderClient
{
public event EventHandler<GetOrderCompletedEventArgs> GetOrderCompleted;

private readonly IAsyncOrderService orderService;

public AsyncOrderClient(IAsyncOrderService orderService)
{
this.orderService = orderService;
}

public void BeginGetOrder(int orderId)
{
orderService.BeginGetOrder(orderId, GetOrderCallback, null);
}

private void GetOrderCallback(IAsyncResult result)
{
Order order = orderService.EndGetOrder(result);
var eh = GetOrderCompleted;
if (eh != null)
eh(this, new GetOrderCompletedEventArgs(order));
}
}

public class GetOrderCompletedEventArgs : EventArgs
{
private readonly Order order;

public GetOrderCompletedEventArgs(Order order)
{
this.order = order;
}

public Order Order { get { return order; } }
}

Listing 9. Asynchronous WCF Service Consumer

Since the BeginGetOrder method is asynchronous, we can notify the caller of the method that the service has completed via an event. This event will be raised when the callback method has been called by the service. The main difference between mocking an asynchronous service from a synchronous one is that the mock must invoke the callback method.

[TestFixture]
public class OrderClientTests6
{
Mock<IAsyncOrderService> orderService;

[SetUp]
public void Setup()
{
orderService = new Mock<IAsyncOrderService>(MockBehavior.Strict);
orderService
.Setup<IAsyncResult>(o => o.BeginGetOrder(It.IsAny<int>(), It.IsAny<AsyncCallback>(), It.IsAny<object>()))
.Returns(() => new Mock<IAsyncResult>().Object)
.Callback
(
(int orderId, AsyncCallback callback, object asyncState) =>
{
orderService
.Setup<Order>(os => os.EndGetOrder(It.IsAny<IAsyncResult>()))
.Returns(new Order { Id = orderId });

var result = new Mock<IAsyncResult>();
callback.BeginInvoke(result.Object, null, null);
}
);
}

[Test]
public void GetOrderTest()
{
var client = new AsyncOrderClient(orderService.Object);
AutoResetEvent waitHandle = new AutoResetEvent(false);
Order asyncOrder = null;
client.GetOrderCompleted +=
(object sender, GetOrderCompletedEventArgs e) =>
{
asyncOrder = e.Order;
waitHandle.Set();
};
client.BeginGetOrder(1);

waitHandle.WaitOne();
waitHandle.Dispose();

Assert.AreEqual(asyncOrder.Id, 1);

orderService.Verify<IAsyncResult>(o => o.BeginGetOrder(It.IsAny<int>(), It.IsAny<AsyncCallback>(), It.IsAny<object>()), Times.Once());
orderService.Verify<Order>(o => o.EndGetOrder(It.IsAny<IAsyncResult>()), Times.Once());
}
}

Listing 10. Testing an Asynchronous Service

Same with the previous tests, we have a mock service. You can see that when we call a method on the mock, we can set it up such that it returns another mock object. In the example, the BeginGetOrder method returns an IAsyncResult mock. We can also add setups on the IAsyncResult mock if we want to, but currently we don’t have any use for it. As mentioned before, we need to invoke the AsyncCallback delegate passed as a parameter to the BeginGetOrder method. This is achieved by using the Callback method. Using lambda expressions, we can get the parameters passed to the BeginGetOrder method, add a setup for the EndGetOrder method, and invoke the callback. Notice that I used BeginInvoke since we are mimicking an asynchronous WCF service. In our test method, we have to wait for the service to finish because it is executing on a separate thread, thus the need for the AutoResetEvent object. Otherwise, our assertions and verifications will fail.

We can also write unit tests for code that uses channel factories, duplex services, out/ref parameters, etc. using Moq. I hope this article helps you in creating tests for these scenarios. You can download the Visual Studio 2010 solution here.

By Michael Detras   Popularity  (7845 Views)
Biography - Michael Detras
.NET developer. Interested in WPF, Silverlight, and XNA.
My blog