Unit testing Web API message handlers

If you have used message handlers within a Web API project then you know they are powerful beasts. They literally give you power to modify requests and responses the way you want. But their implementation makes unit testing slightly difficult. Consider for example following simple message handler.

public class LanguageHandler : DelegatingHandler  
    {
        protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            var cultureCode = request.Headers.AcceptLanguage.First().Value;

            var culture = new CultureInfo(cultureCode);

            Thread.CurrentThread.CurrentCulture = culture;

            return base.SendAsync(request, cancellationToken);
        }
    }

This message handler expects an HTTP header which looks like Accept-Language: en-GB and then uses this information to set culture of the current thread.

A clear problem with unit testing this class is that SendAsync method is protected. we rather encounter this situation lot of times when we need to test a protected or private method. To facilitate this I would create following class in my test project.

internal class LanguageHandlerInternal : LanguageHandler  
        {
            public Task<HttpResponseMessage> SendAyncInternal(HttpRequestMessage request,
                CancellationToken cancellationToken)
            {
                return base.SendAsync(request, cancellationToken);
            }
        }

Now you have got a public method against which you can test and be assured that you are testing the right piece of code. Lets see where that takes us with following test

[Test]
        public void SetsThreadCulture()
        {
            var request = new HttpRequestMessage();
            request.Headers.AcceptLanguage.Add(new StringWithQualityHeaderValue("en-GB"));

            var languageHandler = new LanguageHandlerInternal();

            var response = languageHandler.SendAyncInternal(request, new CancellationToken());

            Assert.That(Thread.CurrentThread.CurrentCulture.Name, Is.EqualTo("en-GB"));
        }

This test fails with error System.InvalidOperationException : The inner handler has not been assigned.. This is down to way message handlers work. This articles and thisexplain internal working of message handlers. Briefly, multiple message handlers are chained together forming a russian doll. Call to base.SendAsync delegates the call to next message handler in line. When executed in the context of a HTTP context, framework ensures that there is a message handler in line always. But during the execution of our unit test, there is no next message handler in line unless we set it. This dummy message handler can be a simple one which when executed returns an HttpResponseMessage with status code Ok.

internal class DummyHandler : DelegatingHandler  
        {
            protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
            {
                return new TaskFactory<HttpResponseMessage>().StartNew(() => new HttpResponseMessage(HttpStatusCode.OK), cancellationToken);
            }
        }

We then set the InnerHandler property of our TestLanguageHandler to this dummy handler as below.

var languageHandler = new LanguageHandlerInternal  
            {
                InnerHandler = new DummyHandler()
            };

If you are testing more complex logic which deals with returnign different responses from mesasge handler e.g. authentication handler that return 401 Unauthorised or pass on the execution, then you can use this dummy handler to mimic what happens after your message handler is done with the request.

I hope you would find these little tricks useful. If you are following a different route to unit test message handlers I am all ears to it, do drop me a line.

The code from this post is on github here

Suhas Chatekar

Discussion

  • Comment with Disqus
  • Comment with Facebook
comments powered by Disqus