Saturday 25 October 2014

Testing WebApi with Owin Hosting

Lately I have been working with the OWIN specification; specifically OWIN hosting, known as Katana, which is Microsoft's implementation of the OWIN specification. During this time I have come across some tools that have helped me create my project. One in particular stood out so I thought I would share.

Brief introduction to Owin hosting

Here is a brief example of OWIN hosting Startup class initializing WebApi, full solution here.

using Owin;
using System.Web.Http;

namespace WebApi
{
    public class Startup
    {
        public void Configuration(IAppBuilder builder)
        {
            HttpConfiguration config = new HttpConfiguration();
            config.Routes.MapHttpRoute("Default", "{controller}/{customerID}", new { controller = "Customer", customerID = RouteParameter.Optional });

            builder.UseWebApi(config);
        }
    }
}

This is the entry point to your API, regardless of being hosted in IIS, Windows Service or even a command window. This is the "first" part of  the code that will be touched in the solution, meaning it's the first place you could break your site unless you have some test covering it.

To learn more about OWIN Katana, see these examples http://www.asp.net/aspnet/samples/owin-katana.

Why is this important?

This pattern of hosting is the future of ASP.net. This is proven with the latest version of vNext using this method.

Testing boundaries

The current trends on testing seem to be in a state of flux. Many people have different views on what the best way of testing is, an argument I'm not trying to take part in here. However, one of these views is to test from the boundaries, not unit testing. In our API's case, the boundaries can be considered as the Startup.cs and likely a database or some external resource. These are the first and last entry points of our solution.

If you want to know more about boundaries, check out Ian Cooper's presentation on Hexagonal Architecture, I saw it at DDD East Anglia and it clarifies a few points of confusion.

Why does the OWIN host make this easy?

One of the NuGets that has come out with the introduction of OWIN host is the Microsoft.Owin.Testing library. With this library we have the ability to call our API from the outside, from the first boundary point of our code.

When using the Mircosoft.Owin.Testing library, the tests are started in an in-memory host. Any calls to the host will now be routed via your "Startup.Configuration" which in our example will pass the calls to the WebApi framework.

This means no setup of a host (IIS, Windows Service...) before you run your test. The tests are completely contained.

Creating a test

  1. Create your API using Owin Hosting, as shown earlier
  2. Create a Unit Test project,
  3. Add a reference to your API project. This allows us to reference the Startup class.
  4. Add the "Microsoft.Owin.Testing" NuGet
  5. Add the following code in your test. Changing the URL to your API url.

var server = TestServer.Create<Startup>();

var response = server.HttpClient.GetAsync("/hello/world").Result;
var result = response.Content.ReadAsAsync<IEnumerable<string>>().Result;

Assert.AreEqual("helloworld", result.First());

Now you can run your test knowing that all your routing and configuration is correct, without setting up any IIS or Service to host your solution.

For some other example see https://github.com/justeat/openrasta-hosting-owin/tree/master/src/OpenRasta.Owin.Test

Not just WebApi

This doesn't just work with WebApi! Any framework that has an OWIN hosting can run within the Microsoft.Owin.Testing in-memory host, here are a couple of frameworks that now allow this.

Conclusion

Whether you want to do integration testing, boundary testing or feature testing I believe that you can use the OWIN in-memory host to achieve this. Removing any prior configuration of a server before running the test also allows for easier collaboration on different machines. With Microsoft following the same patterns in vNext it seems like a promising road map to be on.

**UPDATE**

Since releasing this post I have now been working with JustFakeIt. This is a nice wrapper around a in process host using similar methods as above. The benefit is that we can use it like many mock frameworks with expected results and ignoring parameters. Check it out https://github.com/justeat/JustFakeIt.