ASP.NET Web API

ASP.NET Web API integration testing with in-memory hosting

 http://www.strathweb.com/2012/06/asp-net-web-api-integration-testing-with-in-memory-hosting/

http://zamd.net/2012/05/04/claim-based-security-for-asp-net-web-apis-using-dotnetopenauth/

 

In-memory hosting is one of the hidden gems of ASP.NET Web API. While the community, forums, bloggers have been buzzing about web-host and self-host capabilities of Web API, aside from theterrific post by Pedro Felix, very little has been said about in memory hosting.

Let me show you an example today, how a lightweight Web API server can be temporarily established in memory (without elevated priviliges, or cannibalizing ports like self host) and used to perform integration testing, allowing you to test almost the entire pipeline, from the request to the response.

 

Intro to in memory hosting

In memory hosting comes down to creating an instance of HttpServer class. HttpServer itself is derived from HttpMessageHandler, and can be treated like one. It allows you to perform direct communication between the server runtime, and the client side, through the use of HttpClient orHttpMessageInvoker. As soon as the purpose for the existance of the server is fulfilled, you can very easily dispose of it.

As mentioned, the main advantage of this over self-host, is that it doesn’t require a port or a base address; since by design it doesn’t run on localhost, but truly in memory. You can pretty much mock the entire server environment/runtime in memory!

All this makes in-memory hosting incredibly useful and powerful tool for various testing scenarios, especially for integration testing. It allows you to quickly test the entire processing pipeline of your server, including controllers, filters/attributes, message handlers and formatters. From the moment the HTTP request leaves the client, all the way to the point when the response is received.

We will use integration testing as an example of application of in-memory hosting. A disclaimer here: it will by no means be fullly-fledged, production-ready testing sample or methodology walkthrough; rather my focus here is to show how you can leverage on Web API in-memory hosting to facilitate integration testing scenarios.

My test application

In my test application, I would like to test the following things:
– submitting a request
– a message handler
– custom action filter attribute
– controller action
– JSON formatter applied to the incoming response
– receiving the response

I will scrape the application together from the various pieces of code I have been blogging about over the weeks. The repository will come from this post, the filter will be a simplified version of the caching filter from here, and the handler will be the api key handler from here.

The handler will check for an “apikey”, if the request doesn’t have it, then error will be returned.

 

The filter’s role will be to add cache control directives to the response. That is what I will be checking for in the tests.

 

Setting up test project

My favorite testing framework is xUnit, but obviously any one would do here. Let’s add the test project then, download xUnit and get going.

I will set up the server in the test class’ constructor.

 

The configuration of the in-memory Web API host is almost exactly the same as configuring web- or self- host. You need specify, at the very least, the routes to be used, and that is done through the familiar HttpConfiguration. Server is instantiated by passing the configuration to the HttpServerconstructor.

Notice how I wire up the Message Handler which I will be wanting to test in the server’s configuration. The server’s instance itself will be a private property of the class and will be reused between different test methods.

Since our test class will implementIDisposable, we need to cater for the Dispose method:

 

Now, what I will be testing against is:
– get all items from the repository via GET
– get single item from the repository via POST
– remove single item from the repository via POST
– get all items from the repository via GET without API key (fail on purpose)

In each case we will be starting off by constructing the HttpRequestMessage, sending it to our in memory server, and receiving its response in the form of HttpResponseMessage, which will be used for all kinds of Asserts. What’s important to re-iterate here, this is all simulating the normal end-to-end behavior of the Web API – so in other words a great integration test.

I will be using HttpClient‘s SendAsync method for sending data to the server, since it acceptsHttpRequestMessage, rather than POCO objects, so would allow us to simulate the behavior of the browser.

Before proceeding, I will add up two private helpers, which will be used for constructingHttpRequestMessages to be sent to the server – one for generic HttpRequestMessage and one with an ObjectContent.

 

 

Get all items

 

 

So we create the HttpClient and pass our server to it, as if we were passing the DelegatingHandler – how cool is that? I have an expected JSON response, in the string form, which I will use to compare with the actual result. Then we have a bunch of other asserts:
– response not null
– response content type is “application/json”
– object extracted from the response, IQueryable of Url, contains 3 items (to check if the apikey handler didn’t stop the request)
– two CacheControl asserts (to check if our ActionFilter works)
– comparison to the the expected Json (to check if JSON formatter works)

So, in a few lines of simple code, we have tested so much of the actual, real world functionalities.

Get single item

 

 

This is very similar to the one before, except this time we will be submitting an object. I instantiateUrl object, and send it to the controller. I can serialize the object using JSON.NET and compare the output (the controller returns the added object) – both by reading the content as string and comparing to JSO.NET serialized variable, and by reading the underlying type from the response.

Remove single object

 

 

In this test, I will be removing an item from the repository. This is done by posting an item ID as integer. The controller returns the deleted object instance. Again, I can compare the JSON output to the expected one, as well as extract the underlying POCO object and compare that (in this case I’m just comparing its ID).

Request without apikey

 

 

This last test is an expected failure, as we make a request without providing the apikey. We can verify that the handler works just fine, and that the returned response is a denial of access (403 code).

Running the test

We can now compile the test project, and run the tests in xUnit. Since I am allergic to consoles, let’s use the GUI.

As you can see all the tests pass like a charm. This helps us to verify that it’s not just our unit logic that’s correct, but the entire pipeline behaves like it should. In a few simple methods, we have managed to test so much, by working only with HTTP request and HTTP response; all thanks to in memory hosting.

Summary and source code

As mentioned before, to me in memory hosting is one of the hidden gems of ASP.NET Web API. You should really take advantage of this awesome funcionality. It takes unit/integration testing to new heights, allowing you to produce even more robust applications.

Till next time!

posted @ 2013-07-24 09:43  火腿骑士  阅读(339)  评论(0编辑  收藏  举报