Unit testing OWIN applications using TestServer

Unit testing OWIN applications using TestServer

  • Comments 1

Unit testing OWIN applications using TestServer

Unit testing a OWIN application (pipeline) can be as simple as calling WebApp.Start<T>() on a Startup class. For example here is a simple OWIN pipeline:

using Microsoft.Owin.Hosting;
using Microsoft.Owin.Testing;
using Owin;
using System;
using System.Net.Http;
using Xunit;

namespace OwinApplicationTesting
{
    public class OwinApplicationTests
    {
        [Fact]
        public async void OwinAppTest()
        {
            using (WebApp.Start<MyStartup>("http://localhost:12345"))
            {
                var httpclient = new HttpClient() { BaseAddress = new Uri("http://localhost:12345") };
                HttpResponseMessage response = await httpclient.GetAsync("/");

                //Execute necessary tests
                Assert.Equal<string>("Hello world using OWIN TestServer", await response.Content.ReadAsStringAsync());
            }
        }
    }

    public class MyStartup
    {
        public void Configuration(IAppBuilder app)
        {
            app.UseErrorPage(); // See Microsoft.Owin.Diagnostics
            app.UseWelcomePage("/Welcome"); // See Microsoft.Owin.Diagnostics
            app.Run(async context =>
            {
                await context.Response.WriteAsync("Hello world using OWIN TestServer");
            });
        }
    }
}

You can have this piece of test code in your unit test library and execute the necessary tests. But one drawback with this approach is every time you call WebApp.Start<T>, the test starts a real HTTP listener server and executes the code. What if there is a way by which you can avoid starting a real HTTP server every time, but still unit test the OWIN application pipeline. If that’s what you are looking for, Microsoft.Owin.Testing package solves this problem for you.

Microsoft.Owin.Testing package:

This package contains a TestServer which can create an OWIN request processing pipeline and helpers to submit requests to the pipeline as if it is a real server. Requests made with these helpers never hit the network as they are processed directly in memory. Let’s try to implement the above same test using TestServer.

Install the nuget package ‘Microsoft.Owin.Testing’ using the Nuget package manager into your unit test project. Alternatively you can enter this command in the package manager console:

Install-package Microsoft.Owin.Testing

We are going to use TestServer.Create<T> to create the test server instead of WebApp.Start<T>. To make direct requests to this test server without hitting network, use the HttpClient exposed by this test server instance.

using Microsoft.Owin.Hosting;
using Microsoft.Owin.Testing;
using Owin;
using System;
using System.Net.Http;
using Xunit;

namespace OwinApplicationTesting
{
    public class OwinApplicationTests
    {
        [Fact]
        public async void OwinAppTest()
        {
            using (var server = TestServer.Create<MyStartup>())
            {
                HttpResponseMessage response = await server.HttpClient.GetAsync("/");

                //Execute necessary tests
                Assert.Equal<string>("Hello world using OWIN TestServer", await response.Content.ReadAsStringAsync());
            }
        }
    }

    public class MyStartup
    {
        public void Configuration(IAppBuilder app)
        {
            app.UseErrorPage(); // See Microsoft.Owin.Diagnostics
            app.UseWelcomePage("/Welcome"); // See Microsoft.Owin.Diagnostics 
            app.Run(async context =>
            {
                await context.Response.WriteAsync("Hello world using OWIN TestServer");
            });
        }
    }
}

Requests can also be constructed and submitted with the CreateRequest helper method as below:

HttpResponseMessage response = await server.CreateRequest("/").AddHeader("header1", "headervalue1").GetAsync();

Let’s try to simplify the test further by passing in a lamda for the Configuration method instead of a startup class like below:

using Microsoft.Owin.Testing;
using Owin;
using System.Net.Http;
using Xunit;

namespace OwinApplicationTesting
{
    public class OwinApplicationTests
    {
        [Fact]
        public async void OwinAppTest()
        {
            using (var server = TestServer.Create(app =>
            {
                app.UseErrorPage(); // See Microsoft.Owin.Diagnostics
                app.UseWelcomePage("/Welcome"); // See Microsoft.Owin.Diagnostics
                app.Run(async context =>
                {
                    await context.Response.WriteAsync("Hello world using OWIN TestServer");
                });
            }))
            {
                HttpResponseMessage response = await server.CreateRequest("/").AddHeader("header1", "headervalue1").GetAsync();

                //Execute necessary tests
                Assert.Equal<string>("Hello world using OWIN TestServer", await response.Content.ReadAsStringAsync());
            }
        }
    }
}

How it works?

The HttpClient object that the TestServer helpers use has a special OwinHttpMessageHandler that intercepts all the requests made and converts them into OWIN requests. This OWIN request is being fed to the TestServer directly instead of sending it over the network.

Adding your own client side message handlers:

If you would like to add your own HttpMessageHandler(s) on the client side, you can insert them on the client side pipeline. But as I mentioned in the previous section, to have this TestServer working you need to have the special OwinHttpMessageHandler at the end of the HttpClient pipeline. Here is a sample on how to use your own handlers on the client side:

using Microsoft.Owin.Testing;
using Owin;
using System.Net.Http;
using System.Threading.Tasks;
using Xunit;

namespace OwinApplicationTesting
{
    public class OwinApplicationTests
    {
        [Fact]
        public async void OwinAppTest()
        {
            using (var server = TestServer.Create(app =>
            {
                app.UseErrorPage(); // See Microsoft.Owin.Diagnostics
                app.UseWelcomePage("/Welcome"); // See Microsoft.Owin.Diagnostics
                app.Run(async context =>
                {
                    if (context.Request.Headers.Get("Header1") == "HeaderValue1")
                    {
                        await context.Response.WriteAsync("Hello world using OWIN TestServer");
                    }
                    else
                    {
                        await context.Response.WriteAsync("Header missing");
                    }
                });
            }))
            {
                var httpClient = new HttpClient(new AddHeaderHttpHandler(server.Handler));
                var response = await httpClient.GetAsync("http://localhost:1234/");

                //Execute necessary tests
                Assert.Equal<string>("Hello world using OWIN TestServer", await response.Content.ReadAsStringAsync());
            }
        }
    }

    public class AddHeaderHttpHandler : DelegatingHandler
    {
        public AddHeaderHttpHandler(HttpMessageHandler handler)
            : base(handler)
        {
        }

        protected async override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
        {
            request.Headers.Add("Header1", "HeaderValue1");
            return await base.SendAsync(request, cancellationToken);
        }
    }
}

OWIN environment object as a request:

Alternative to using CreateRequest() or HttpClient to send request, you can send an OWIN environment dictionary directly as a request by using the following overload of TestServer.

server.Invoke(yourOwinEnvironmentDictionary);

  • Could you please add syntax highlighting to your C# code? Thanks.

Page 1 of 1 (1 items)