Tuesday 30 April 2013

Using Web API filter for Polymorphic results

When starting a little deeper with Web API I found a block on the road: if I returned any object different of the return type declared in the action method signature, then the serialization mechanism throw an exception related to the type instantiated is not expected, the error message is like this: "Type 'Mvc4AppFilter.Models.Student' with data contract name 'Student:http://schemas.datacontract.org/2004/07/Mvc4AppFilter.Models' is not expected. Consider using a DataContractResolver or add any types not known statically to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to DataContractSerializer." when trying to serialize as XML, JSON works like a charm, why is this happening?
If we find the source code for class System.Net.HttpHttpRequestMessageExtensions at method with this signature, because there are several overloads:
public static HttpResponseMessage CreateResponse<T>(this HttpRequestMessage request, HttpStatusCode statusCode, T value, HttpConfiguration configuration)
We found the things related to content negotiation and checking for proper values from configuration, but at the end there's something like this:
return new HttpResponseMessage
{
    Content = new ObjectContent<T>(value, result.Formatter, mediaType),
    StatusCode = statusCode,

    RequestMessage = request
};
and the key point is that if the typeof(T) is not equal to value.GetType() then the ObjectContent throws the exception because of the mismatching of types and that occurs when for example we declare the method with return type Person and for some reason we return either a Worker object or Student object (where both inherit from Person)

The first solution was to extract the important sentences from this source code and create my own extension for CreateResponse and using the ObjectContent non generic version, but later I decided to group this code in a Filter, in this case an Action filter, and it will be executed after each action is executed, the goal is to transform the any object return type action to a properly configured HttpResponseMessage. Here's the code.
public class HttpResponseFilter : ActionFilterAttribute
{
    public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
    {
        var request = actionExecutedContext.Request;
        var response = actionExecutedContext.Response;
        if (response.Content != null && !response.Content.IsHttpResponseMessageContent() && response.Content is ObjectContent) 
        {
            var objContent = response.Content as ObjectContent;
            var value = objContent.Value;
            var result = request.CreateResponse(System.Net.HttpStatusCode.OK);
            if (value != null)
            {
                var config = request.GetConfiguration();
                var negociator = config.Services.GetContentNegotiator();
                var nresult = negociator.Negotiate(value.GetType(), request, config.Formatters);
                result.Content = new ObjectContent(value.GetType(), value, nresult.Formatter);
            }
            actionExecutedContext.Response = result;
        }
    }
}

Finally, we need to register the filter in application startup, i.e. in the file out of the box WebApiConfig.cs by adding this line:
config.Filters.Add(new HttpResponseFilter());
Hope it helps you to improve your code, the source can be downloaded here.

Monday 1 April 2013

Mocking a repository using RhinoMocks

Unit testing is often a tedious and repetitive task, even if we are testing controllers for Web API, the main goal for the code to be testable is the separation of concerns, so the parts can be tested separately and in an isolated way. To achieve this it's necessary to supply the dependencies to our target testing code. Here is where the mocks come to the scene.

One code that is usually mocked is the repositories, the mocked objects are in the form: when the method X is invoked with argument Y then return Z, or something around that. An actual repository can be mocked using an in memory list of the same entity.

We can do this by two ways: one is to implement the repository interface with an actual class that hides that in memory list, but as the application grows, the number of these fake classes will grow too, I discourage this practice as non-scalable. The other way is to use a mocking framework and there are a lot of them and can be found at nuget, I'll use RhinoMocks for this post.

The code for mocking can be quite cryptic using this kind of framework, but in the long term is better than writing actual fake code, the goal for faking repositories is to keep the data consistency so if we add a new item to the list, we can verify the count and see that there is one more or if we remove one item, and so on.

Let's start with the repository interface, this is very simple repository in order to have less things to do in the example and keep complexity off.
    
    public interface IIdentityKey<Tkey>
    {
        TKey Id { get; }
    }
    public interface IRepository<Tkey,TEntity> where TEntity : IIdentityKey<Tkey>
    {
        IQueryable<TEntity> All();

        TEntity FindBy(TKey id);

        TEntity Add(TEntity entity);

        void Update(TEntity entity);

        void Delete(TEntity entity);
    }

In our controller we use this interface as it will be injected using any IoC such as Ninject, but important here is that the controller doesn't know or even cares the actual implementation of this repository, this is a fragment of our controller:
    
    public class PersonController : ApiController
    {
        private readonly IRepository<long, Person> _repository;  

        public PersonController(IRepository<long, Person> repository)
        {
            _repository = repository;
        }

        // GET api/person
        public IEnumerable<Person> Get()
        {
            return _repository.All().ToArray();
        }

        // the rest of the code removed for brevity ...
    }

Now it's the time for constructing the mock object, but first a quick recipe on using RhinoMocks for creating mock objects:

    MockRepository mocks = new MockRepository();
    IRepository<long, Person> repo = mocks.Stub<IRepository<long, Person>>();
    using (mocks.Record())
    {
        // Method constructing here
    }

We need to create the 5 methods previously mentioned in the interface in a way that they make the operations on a list with initial data, such as this:

    private List<Person> _fakedata = new List<Person> {
        new Person { Id = 1, Name = "Person1", Email = "person1@nomail.com" },
        new Person { Id = 2, Name = "Person2", Email = "person2@nomail.com" },
        //  ( ... )
        new Person { Id = 8, Name = "Person8", Email = "person8@nomail.com" }
    };

Or if the objects are more complex with relationships, might be using for loop, nonetheless the data is created. Let's see the method stubs for the operations to be mocked, for that, we use the combination of the the Stub(...).Return(...) and Stub(...).Do(...) the easiest operation is the Get without parameters and looks like this:

// setup All method
repo.Stub(x => x.All()).Return(_fakedata.AsQueryable());

Here we are just saying, when you call the method All, then return the _fakedata object as queryable, this simple because the method have no parameters. Let's see now the Add method, which has a parameter and returns a value, it's intended to accept the object that is to be added and returns the object in a state after inserted.

    // setup Add method
    repo.Stub(x => x.Add(Arg<Person>.Is.Anything))
        .Do(new Func<Person, Person>(
            x =>
            {
                _fakedata.Add(x);
                return _fakedata.Last();
            }
        ));

In this operation we tell to the mock that when the Add method is invoked with an argument of type Person without any constraint, at this point it can be set any kind of constraint like if is null or not null or equals or greater than, etc. but as we are mocking the operation for customize the action, we use no constraint. The Do accepts a generic delegate, that's why it's necessary to specify the concrete delegate like Func<Person,Person> that matches the signature of the operation we want to mock and the parameter expressed as a lambda expression where x is the only parameter, the logic is simple but we can include more realistic work like set the Id by getting the maximum Id and adding one, the key point here is to add the item to our list.

Using a similar technique we can implement the Update, FindBy and Delete operations, as follows:

    // setup Update method
    repo.Stub(x => x.Update(Arg<Person>.Is.Anything))
        .Do(new Action<Person>(x =>
        {
            var i = _fakedata.FindIndex(q => q.Id == x.Id);
            _fakedata[i] = x;
        }));

    // setup FindBy
    repo.Stub(x => x.FindBy(Arg<long>.Is.Anything))
        .Do(new Func<long, Person>(
            x => _fakedata.Find(q => q.Id == x)
        ));

    // setup Delete
    repo.Stub(x => x.Delete(Arg<Person>.Is.Anything))
        .Do(new Action<Person>(
            x => _fakedata.Remove(x)
        ));

Now, the test should look like this fragment:

    [TestMethod]
    public void Get()
    {
        // Arrange
        PersonController controller = CreateController();

        // Act
        IEnumerable<Person> result = controller.Get();

        // Assert
        Assert.IsNotNull(result);
        Assert.AreEqual(8, result.Count());
        Assert.AreEqual("Person1", result.ElementAt(0).Name);
        Assert.AreEqual("Person8", result.ElementAt(7).Name);
    }

    [TestMethod]
    public void GetById()
    {
        // Arrange
        PersonController controller = CreateController();

        // Act
        Person result = controller.Get(5);

        // Assert
        Assert.AreEqual("Person5", result.Name);
    }

Where the CreateController method contains all the logic previously described and returns a new instance of the controller with the mocked object passed as parameter in the constructor, The sample code can be downloaded here.