Parameterized Tests for ServiceStack Web Services

February 18, 2012 | Unit Testing | AutoFixture

I have been using ServiceStack's RestServiceBase class with great success. Because of that I started looking for ways to automate a Layer Test for a simple scenario where a client requests a representation of a resource using GET and/or submits data to be processed to the identified resource using POST.

public class CategoryService : RestServiceBase<Category>
{
    public override object OnGet(Category request)  { /* ... */ }
    public override object OnPost(Category request) { /* ... */ }
}

I found a very nice entry on the wiki and after writting a couple of tests I realized that I was repating the following steps over and over:

var restClient = (IRestClient)new JsonServiceClient("http://localhost:5000");

One solution is to have the base URI (and even the IRestClient) on a private field inside the test class and use it from all tests. However, a better approach would be to write Parameterized Tests that accept an instance of the IRestClient type.

Fortunately, this can be done using xUnit.net data theories. Furthermore, since the IRestClient is an interface, this is a great scenario for using AutoFixture together with xUnit.net data theories and auto mocking.

Below is a parameterized test:

[Theory, AutoWebData]
public void HttpGetReturnsnNonEmptyResult(IRestClient sut)
{
    var results = sut.Get<Category[]>("/categories");
    Assert.True(results.Any());
}
[Theory, AutoWebData]
public void HttpGetReturnsNonEmptyResultWithId(IRestClient sut)
{
    var expectedId = sut.Get<Category[]>("/categories").First().Id;
    var result = sut.Get<Category>("/categories/" + expectedId);
    Assert.Equal(expectedId, result.Id);
}

The AutoWebData attribute provides auto-generated data specimens generated by AutoFixture as an extention to xUnit.net's Theory attribute.

public sealed class AutoWebDataAttribute : AutoDataAttribute
{
    public AutoWebDataAttribute()
        : base(new Fixture().Customize(new WebModelCustomization()))
    {
    }
}

Inside this attribute class we also pass a new instance of the Fixture class customized in order to supply an instance of the JsonServiceClient when an IRestClient is requested. (You can read more about AutoFixture Customizations here.)

public class WebModelCustomization : CompositeCustomization
{
    public WebModelCustomization()
        : base(
            new RestClientCustomization(),
            new AutoMoqCustomization()) { } 

    private sealed class RestClientCustomization : ICustomization
    {
        public void Customize(IFixture fixture)
        {
            fixture.Inject<IRestClient>(
                new JsonServiceClient("http://localhost:5000"));
        }
    }
}

The advantage of this approach is that we have abstracted the creation of the IRestClient instance from the test itself. The base URI is now hardcoded in only one place (the customization class). Furthermore, we can easily pass other parameters to the test method if necessary. 

While this approach is applied to ServiceStack it can be easily generalized and used on other scenarios as well.