Kash Farooq's software development blog

.NET Developer

Stubbing RESTful services with WCF (Part 2)

Posted by Kash Farooq on July 9, 2012

A three part series.

  • Part 1: The set-up. Setting up an example to show what we are trying to stub.
  • Part 2: Creating a service stub.
  • Part 3: Using the service stub from a test.

Part 1 explained what we are trying to stub – and the first step in creating a service stub is to create a Service Contract interface that looks like the RESTful service we want to stub:

[ServiceContract]
public interface IServiceStub
{
  [WebInvoke(ResponseFormat = WebMessageFormat.Xml, UriTemplate = "OrderingSystem/{entityType}/{entityId}", BodyStyle = WebMessageBodyStyle.Bare, Method = "GET")]
  [OperationContract]
  XElement GetEntity(string entityType, string entityId);

  [WebInvoke(ResponseFormat = WebMessageFormat.Xml, UriTemplate = "OrderingSystem/{entityType}/{entityId}/{childEntityType}", BodyStyle = WebMessageBodyStyle.Bare, Method = "GET")]
  [OperationContract]
  XElement GetChildEntity(string entityType, string entityId, string childEntityType);
}

ServiceContractAttribute is in System.ServiceModel and WebInvokeAttribute is in System.ServiceModel.Web,

The UriTemplate properties in the Service Contract match the RESTful URIs we need to hit, e.g. http://localhost:7000/OrderingSystem/Order/2 (getting a specific order) and http://localhost:7000/OrderingSystem/Order/2/Orderlines (getting child order lines for a specific order).

Next we need a service stub that implements this interface:

[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
public class ServiceStub : IServiceStub
{
  public XElement GetEntity(string entityType, string entityId)
  {
    //TODO: implement
  }

  public XElement GetChildEntity(string entityType, string entityId, string childEntityType)
  {
    //TODO: implement
  }
}

Our tests will bring this service up (listening on port 7000) using WCF’s ServiceHost. The test code can then hit public methods that call down through application layers to the point where a layer would normally hit the RESTful service. However, rather than hitting the real service it will hit this stub.

So, we need a method in ServiceStub for the tests to call that will bring up the service and a corresponding method to stop it. Let’s add these method to the ServiceStub class:

private ServiceHost serviceHost;
public void Start()
{
  serviceHost = new ServiceHost(this, new Uri("http://localhost:7000"));
  var serviceEndpoint = serviceHost.AddServiceEndpoint(typeof(IServiceStub), new WebHttpBinding(), string.Empty);
  serviceEndpoint.Behaviors.Add(new WebHttpBehavior());
  serviceHost.Open();
}

public void Stop()
{
  serviceHost.Close();
}

ServiceStub will need to return stubbed data, so it needs methods to allow the tests to insert test data into the stub. Then, when GetEntity and GetChildEntity are called they can return that stubbed data. We’ll do this by providing a couple of Add methods to add Orders and Order Lines to the stub. I’ll store the stub data in dictionaries:

private readonly Dictionary<int, Order> orders = new Dictionary<int, Order>(); //key is order ID
private readonly Dictionary<int, OrderLines> ordersLinesDictionary = new Dictionary<int, OrderLines>(); //key is order ID
private readonly Dictionary<int, OrderLine> ordersLineDictionary = new Dictionary<int, OrderLine>(); //key is orderline ID
public void Add(Order order)
{
  orders.Add(order.Id,order);
}

public void Add(int orderId,OrderLines orderLines)
{
  foreach (var orderLine in orderLines.ArrayOfOrderLines)
  {
    ordersLineDictionary.Add(orderLine.Id,orderLine);
  }
  ordersLinesDictionary.Add(orderId,orderLines);
}

Finally, lets implement the GetEntity and GetChildEntity methods. They will take data from the dictionaries and serialize it – returning it as XML:


public XElement GetEntity(string entityType, string entityId)
{
  if (entityType=="Order")
  {
    return ObjectSerializer.Serialize(orders[Convert.ToInt32(entityId)]);
  }
  if (entityType=="Orderline")
  {
    return ObjectSerializer.Serialize(ordersLineDictionary[Convert.ToInt32(entityId)]);
  }
  throw new NotSupportedException();
 }

public XElement GetChildEntity(string entityType, string entityId, string childEntityType)
{
  if (entityType=="Order" && childEntityType=="Orderlines")
  {
    return ObjectSerializer.Serialize(ordersLinesDictionary[Convert.ToInt32(entityId)]);
  }
  throw new NotSupportedException();
}

When GetEntity or GetChildEntity is called, the code checks which entity was requested, grabs it out of the correct dictionary, serializes it with a helper class I created (see below) and returns it.

The final post in this series will demonstrate the usage of the Service Stub.

For completeness, here is the full ServiceStub class and the ObjectSerializer class:

public class ObjectSerializer
{
  public static XElement Serialize(object objectToSerialize)
  {
    using (var memoryStream = new MemoryStream())
    {
      var xmlSerializer = new XmlSerializer(objectToSerialize.GetType());
      xmlSerializer.Serialize(memoryStream, objectToSerialize);
      memoryStream.Flush();
      memoryStream.Seek(0, SeekOrigin.Begin);
      return XElement.Load(memoryStream);
    }
  }
}
<pre>[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
public class ServiceStub : IServiceStub
{
  private readonly Dictionary<int, Order> orders = new Dictionary<int, Order>(); //key is order ID
  private readonly Dictionary<int, OrderLine> ordersLineDictionary = new Dictionary<int, OrderLine>(); //key is orderline ID
  private readonly Dictionary<int, OrderLines> ordersLinesDictionary = new Dictionary<int, OrderLines>(); //key is order ID
  private ServiceHost serviceHost;

  public XElement GetEntity(string entityType, string entityId)
  {
    if (entityType == "Order")
    {
      return ObjectSerializer.Serialize(orders[Convert.ToInt32(entityId)]);
    }
    if (entityType == "Orderline")
    {
      return ObjectSerializer.Serialize(ordersLineDictionary[Convert.ToInt32(entityId)]);
    }
    throw new NotSupportedException();
  }

  public XElement GetChildEntity(string entityType, string entityId, string childEntityType)
  {
    if (entityType == "Order" && childEntityType == "Orderlines")
    {
      return ObjectSerializer.Serialize(ordersLinesDictionary[Convert.ToInt32(entityId)]);
    }
    throw new NotSupportedException();
  }

  public void Start()
  {
    serviceHost = new ServiceHost(this, new Uri("http://localhost:7000"));
    var serviceEndpoint = serviceHost.AddServiceEndpoint(typeof (IServiceStub), new WebHttpBinding(), string.Empty);
    serviceEndpoint.Behaviors.Add(new WebHttpBehavior());
    serviceHost.Open();
  }

  public void Stop()
  {
    serviceHost.Close();
  }

  public void Add(Order order)
  {
    orders.Add(order.Id, order);
  }

  public void Add(int orderId, OrderLines orderLines)
  {
    foreach (var orderLine in orderLines.ArrayOfOrderLines)
    {
      ordersLineDictionary.Add(orderLine.Id, orderLine);
    }
    ordersLinesDictionary.Add(orderId, orderLines);
  }
}

Right. We have our stub. Now on to Part 3 where we’ll use it from a test.

Advertisements

Sorry, the comment form is closed at this time.

 
%d bloggers like this: