Kash Farooq's software development blog

.NET Developer

Posts Tagged ‘Stubbing RESTful Services’

Stubbing RESTful services with WCF (Part 3)

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 REST service stub.
  • Part 3: Using the service stub from a test.

In this final part of the series, I’ll use the ServiceStub class created in Part 2 to create a full end-to-end test.

I want to create an Order Query System that uses the data provided by the RESTful URI to return some consolidated data.

Here is a very simple example to start with – the Order Query System provides a method that calculates how old an order is.  My test code needs to bring up the service stub, populate it with some stub data, call the Order Query System and then stop the service stub.:

[TestFixture]
public class TestCode
{
  private ServiceStub serviceStub;

  [TestFixtureSetUp]
  public void TestFixtureSetUp()
  {
    serviceStub = new ServiceStub();
    serviceStub.Start();
  }

  [TestFixtureTearDown]
  public void TestFixtureTearDown()
  {
    serviceStub.Stop();
  }

  [Test]
  public void GetNumbersOfDaysSinceOrderPlaced()
  {
    DateTime orderDate = DateTime.Now.AddDays(-100);
    var order = new Order {Id = 1, OrderDate = orderDate, OrderLinesRef = "http://localhost:7000/OrderingSystem/Order/1/Orderlines" };
    serviceStub.Add(order);

    var orderQuerySystem = new OrderQuerySystem();
    var daysSinceOrderPlaced = orderQuerySystem.GetNumberOfDaysSinceOrderWasPlaced(1);

    daysSinceOrderPlaced.Should().Be(100);
  }
}

I bring the service stub up in the Test Fixture Set-up and close it down in the corresponding tear down method. In the test, I create some dummy data and add it to the stub. I then call the Order Query System  and do my my assert.

And the method in the OrderQuerySystem class:

public class OrderQuerySystem
{
  public int GetNumberOfDaysSinceOrderWasPlaced(int orderId)
  {
    var gateway = new RestServiceGateway();
    var order = gateway.GetOrder(orderId);
    return (DateTime.Now - order.OrderDate).Days;
  }
}

The Order Query System uses the RestServiceGateway (implementation omitted – I’ll give this at the end of the post for completeness) to get the data it needs to fulfil the query.

Here is an example that requires me to navigate to the child entity. I’ll call a Order Query System method that returns the number of order lines that a particular order has – this means I need to stub both the order and the order lines belonging to that order:

[Test]
public void GetNumbersOfOrderLinesForAnOrder()
{
   var order = new Order { Id = 2, OrderDate = DateTime.Now, OrderLinesRef = "http://localhost:7000/OrderingSystem/Order/2/Orderlines" };
   var orderLine1 = new OrderLine { Id = 21, OrderRef = "http://localhost:7000/OrderingSystem/Order/2"};
   var orderLine2 = new OrderLine { Id = 22, OrderRef = "http://localhost:7000/OrderingSystem/Order/2"};
   var orderLine3 = new OrderLine { Id = 23, OrderRef = "http://localhost:7000/OrderingSystem/Order/2"};
   var orderLines = new OrderLines {ArrayOfOrderLines = new[] {orderLine1, orderLine2, orderLine3}};
   serviceStub.Add(order);
   serviceStub.Add(order.Id,orderLines);

   var orderQuerySystem = new OrderQuerySystem();
   var numberOfOrderLines = orderQuerySystem.GetNumberOfOrderLinesFor(2);

   numberOfOrderLines.Should().Be(3);
}

And the corresponding method in the OrderQuerySystem class:

public class OrderQuerySystem
{
  public int GetNumberOfOrderLinesFor(int orderId)
  {
    var gateway = new RestServiceGateway();
    var order = gateway.GetOrder(orderId);
    var orderlines = gateway.GetEntity<OrderLines>(order.OrderLinesRef);
    return orderlines.ArrayOfOrderLines.Length;
  }
}

In the above example, the system under test code has to navigate to a child entity based on a ref provided by the parent entity.

And that’s it. On a recent project I’ve created some rock-solid integration tests using this technique.

For completeness, here is the RestServiceGateway class:

public class RestServiceGateway
{
  private const string EntityAddress = "http://localhost:7000/OrderingSystem/{0}/{1}";
  private const string ChildEntityAddress = "http://localhost:7000/OrderingSystem/{0}/{1}/{2}";

  public Order GetOrder(int orderId)
  {
    return GetEntity<Order>(string.Format(EntityAddress,"Order",orderId));
  }

  public OrderLine GetOrderLine(int orderlineId)
  {
    return GetEntity<OrderLine>(string.Format(EntityAddress, "Orderline", orderlineId));
  }

  public OrderLines GetOrderLinesFor(int orderId)
  {
    return GetEntity<OrderLines>(string.Format(ChildEntityAddress, "Order", orderId, "Orderlines"));
  }

  public T GetEntity<T>(string entityAddress)
  {
    var xmlSerializer = new XmlSerializer(typeof (T));
    var xmlReader = XmlReader.Create(entityAddress);
    var entity = (T) xmlSerializer.Deserialize(xmlReader);
    return entity;
  }
}
Advertisements

Posted in .NET, Test Driven Development, WCF | Tagged: , , , | Leave a Comment »

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.

Posted in .NET, Test Driven Development, WCF | Tagged: , , , , | Leave a Comment »

Stubbing RESTful services with WCF (Part 1)

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 REST service stub.
  • Part 3: Using the service stub from a test.

In this post I will provide the “set-up” for the later posts – basically this post will explain what I am trying to stub by giving some URI, Model and XML examples.

Firstly, here is the simple object model that the RESTful service returns as XML. Essentially we have an order which contains some order lines. Each order includes a URI to the child resource – i.e. to an array of order lines, and each order line has a URI back to the parent resource – i.e. to the parent order. I’m going to create a “Order Query System” – the system under test – that uses the RESTful service to retrieve data and I will need to stub it to create some robust and consistently repeatable integration tests.

public class Orders
{
  public Order[] ArrayOfOrders { get; set; }
}

public class Order
{
  public int Id { get; set; }
  public DateTime OrderDate { get; set; }
  public string OrderLinesRef { get; set; }
}

public class OrderLines
{
  public OrderLine[] ArrayOfOrderLines { get; set; }
}

public class OrderLine
{
  public int Id { get; set; }
  public string OrderRef { get; set; }
}

To get an order with ID=2, we hit the RESTful URI http://localhost:7000/OrderingSystem/Order/2. The following XML document returned is:

<?xml version="1.0" encoding="utf-8"?>
<Order xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <Id>1</Id>
  <OrderDate>2012-06-03T19:14:06.4383397+01:00</OrderDate>
  <OrderLinesRef>http://localhost:7000/OrderingSystem/Order/2/Orderlines</OrderLinesRef>
</Order>

If the client then follows the OrderLinesRef URI to http://localhost:7000/OrderingSystem/Order/2/Orderlines, the following XML, containing all the order lines that belong to Order 2, is returned :

<?xml version="1.0" encoding="utf-8"?>
<OrderLines xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <ArrayOfOrderLines>
    <OrderLine>
      <Id>21</Id>
      <OrderRef>http://localhost:7000/OrderingSystem/Order/2</OrderRef>
    </OrderLine>
    <OrderLine>
      <Id>22</Id>
      <OrderRef>http://localhost:7000/OrderingSystem/Order/2</OrderRef>
    </OrderLine>
    <OrderLine>
      <Id>23</Id>
      <OrderRef>http://localhost:7000/OrderingSystem/Order/2</OrderRef>
    </OrderLine>
  </ArrayOfOrderLines>
</OrderLines>

Finally, if you hit the URI for a specific order line, e.g. http://localhost:7000/OrderingSystem/Orderline/22, the data just for order line 22 are returned:

<?xml version="1.0" encoding="utf-8"?>
<OrderLine xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <Id>22</Id>
  <OrderRef>http://localhost:7000/OrderingSystem/Order/2</OrderRef>
</OrderLine>

Right. Now on to the next part 2: creating a Service Stub that returns data like the above XML examples for the various URIs.

Posted in .NET, Test Driven Development, WCF | Tagged: , , , , | Leave a Comment »