Friday, September 10, 2010
 

Search
Latest entries in the Euricom Team blog
May 8

Written by: Euricom
5/8/2009 1:31 PM 

 

The context

As was discussed in part 3 of this series the purpose of our efforts was to set up a way to drive acceptance test from the UI on top of a complex legacy system. To make things more tempting the system contains a lot of dependencies to a several external systems.

This post will talk about some of the technical aspects of the solution. Other technical posts will certainly follow.
In the test scenario’s we didn’t want to include actual calls to these external systems for reasons explained in part 3. So we came up with the following picture:
 

Process view

 

In short:

  • The server logic was taken in-process, needed to enable mocking.
  • Mocks where created for external systems
 
A combination of Unity and Rhino.Mocks was used to achieve this.
 

Server logic in-process with test execution

As was told earlier an interface was extracted for the webservice proxy and implemented by both the webservice and its proxy.
In real-time (production) the UI needs to instantiate the proxy: out-of-process; during automated testing the proxy needs to be bypassed and the front server web methods are called directly: in-process.
 
There is a problem with this approach though. Taking server logic in-process can cause side effects. Say an object is passed to such a webservice method. Let’s assume that during processing the server changes the state of this object. In the normal out-of-process mode the client would not see these changes unless the object would be passed by reference. But in the in-process mode the client now gets to know these changes. This results in a different behavior and of course this needs to be avoided. That’s where the first application of Unity comes into play, interception
 

Interception

The solution for the above problem is to ‘mimic’ out-of-process execution. This can be done by serialization/deserialization of all serializable objects that are passes to or returned from the front server.
To do so we need to intercept every call to a server method. Unity’s InterfaceInterceptor is ideal for such a scenario. Following are the needed steps.
 
In the actual code:
  • Create a SerializeDataAttribute: used to decorate the interfaces methods
  • Create SerializeDataHandler: Executing the actual interception code : in memory serialization/deserialization of objects
  • Decorate all the methods of the extracted serer/proxy interface with the SerializeDataAttribute.
  • Register webservice proxy as the concrete type in unity, using configuration or in code.
  • Use unity to resolve the concrete instance for the interface

In the test code:

  • Override unity registration of the interfaces in the unity container, telling it to instantiate the webservice class directly.
  • Add the interception extension to unity
  • Link the InterfaceInterceptor to the decorated interface
 
SerializeDataAttribute and SerializeDataHandler
 
public class SerializeDataAttribute : HandlerAttribute
{
    public override ICallHandler CreateHandler(IUnityContainer container)
    {
        return new SerializeDataHandler();
    }
}
 
public class SerializeDataHandler : ICallHandler
{
    public int Order { get; set; }
 
    public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
    {
        // Serialize/deserialize the input arguments
        for (int i = 0; i < input.Arguments.Count; i++)
        {
          ParameterInfo parameterInfo = input.Arguments.GetParameterInfo(i);
            if (!parameterInfo.IsOut && !parameterInfo.IsRetval)
            {
                SerializeTarget(i, input.Arguments, GetParameterType(parameterInfo));
            }
        }
 
        // Call the actual method
        IMethodReturn methodReturn = getNext()(input, getNext);
 
        // If the method returned an exception, throw it
        if (methodReturn.Exception != null)
        {
            throw methodReturn.Exception;
        }
 
        // Serialize/deserialize the output arguments
        for (int i = 0; i < methodReturn.Outputs.Count; i++)
        {
            ParameterInfo parameterInfo = methodReturn.Outputs.GetParameterInfo(i);
 
            SerializeTarget(i, methodReturn.Outputs, GetParameterType(parameterInfo));
        }
 
        // Serialize/deserialize the return value
        methodReturn.ReturnValue = CopyTarget(methodReturn.ReturnValue, ((MethodInfo)input.MethodBase).ReturnType);
 
        // Return
        return methodReturn;
    }
 
 
Notice:
  • SerializeTarget and CopyTarget are private methods that do the actual serialization/deserialization. The actual implementation goes beyond the scope of this post. It uses an XmlSerializer, MemoryStream and XmlTextReader.
  • Exceptions need to be rethrown. 
 
 
Interface decoration
 
public interface ISomeService
{
    [SerializeData]
    void UpdateCustomer(object Customer);
}
 
 
 
Register webservice proxy
 
IUnityContainer container = new UnityContainer();
container.RegisterType<ISomeService, SomeServiceWse>();
 
 
 
Resolve the concrete instance
 
ISomeService someService = container.Resolve<ISomeService>();
someService.UpdateCustomer(customer);
 
 
 
Test code, Override unity registration and set InterfaceInterceptor
 
container.RegisterType<ISomeService, SomeService>();
 
container.AddNewExtension<Interception>();
 
container.Configure<Interception>()
.SetInterceptorFor<ISomeService>(new InterfaceInterceptor());
 
 
 
That’s all to it. In normal execution the webservice proxy is instantiated. No interception is taking place so no overhead there, because the InterfaceInterceptor is not configured.
 
During test execution, the webservice is instantiated, calls to it are intercepted and objects are serialized.
 
 
 
Mocking external systems
 
Now we are ready to mock. Since the server is running in-process we can use Unity to inject the mocked backend systems.
The actual detailed process of setting up mocking, using Rhino or another mocking framework, goes beyond the scope of this post.
 
In short what is needed is the following:
  • Extract or create an interface of the backend systems.
  • Use and configure unity to instantiate the correct instance: in real-time the backend system, during test the mocked one. As in the above example this involves calls to IUnityContainer.RegisterType and Resolve methods.
  • Setup the tests to create the mock, record and playback.
 
In conclusion we can say that the use of Unity was a great help making a large complex legacy system testable, while it was not designed (at all) with automated testing in mind.
 

 By Peter Notenbaert, .Net Solutions Architect

Tags:

Your name:
Your email:
(Optional) Email used only to show Gravatar.
Your website:
Title:
Comment:
Add Comment   Cancel 
Copyright (c) 2010 Euricom ::Terms Of Use::Privacy Statement