Damian Hickey

Mostly software and .NET related. Mostly.

Testing Nancy with Owin.Testing

I always like a challenge :)

Nancy has a very nice way of testing, including a mechanism to configure the application as required for each test (swap in a mock etc). It does this with the Browser class:

[Fact]
public void NancyTest()
{
	// Arrange
	var browser = new Browser(with => with.Module<ConfigBootTestModule>());

	// Act
	BrowserResponse response = browser.Get("/config");

	// Assert
	Assert.Equal("Hello configured fellow", response.Body.AsString());
}

(The 'with => ' lambda here is altering the configurable boostrapper)

If you are hosting Nancy with OWIN, and you are using other middleware, you may prefer to test with Owin.Testing for broader test scope. I should state that Owin.Testing was indeed inspired by Nancy.Testing in the first place - I wanted to do the same type of testing with my OWIN application that was possible with Nancy.

So first let's create our OWIN startup class. Here, we are injecting the INancyBootstrapper which will allow us to supply a configurable one in a test:

private class Startup
{
	private readonly INancyBootstrapper _nancyBootstrapper;

	public Startup(INancyBootstrapper nancyBootstrapper)
	{
		_nancyBootstrapper = nancyBootstrapper;
	}

	public void Configuration(IAppBuilder builder)
	{
		builder.UseNancy(_nancyBootstrapper);
	}
}

We're going to add a helper method to configure the bootstraper, to make our test read more like the Nancy Browser example above:

private static HttpClient CreateHttpClient(Action<ConfigurableBootstrapper.ConfigurableBootstrapperConfigurator> configureBootstrapperAction)
{
	return OwinTestServer.Create(builder => 
		new Startup(new ConfigurableBootstrapper(configureBootstrapperAction)).Configuration(builder))
		.CreateHttpClient();
}

Here we are creating our test server, configuring the boostrapper via supplied action and returning an HttpClient.

And the Owin.Testing equivalent test:

public async Task OwinTest()
{
	// Arrange
	var httpClient = CreateHttpClient(with => with.Module<ConfigBootTestModule>());

	// Act
	var response = await httpClient.GetAsync("http://localhost/config");
	var body = await response.Content.ReadAsStringAsync();

	// Assert
	Assert.Equal("Hello configured fellow", body);
}

Looks familiar, doesn't it? ;)

Full gist.

Introducing Owin.Testing

Owin.Testing is discontinued. Use Microsoft.Owin.Testing instead.

Continuing in my mini-series of introductions, Owin.Testing (nuget, github) is an OSS helper library to host your OWIN application and, by using Owin.HttpMessageHandler, make in-memory testing of OWIN applications simple, fast, and environment dependency free. The method by which your application is invoked is using an HttpClient - a similar mechansim from which your users will be interacting with your application. Cookies support is supported by default (and can be turned off).

An example best demonstrates how this works:

//Arrange
OwinTestServer owinTestServer = OwinTestServer.Create(builder => new Startup().Configuration(builder));
HttpClient httpClient = owinTestServer.CreateHttpClient();

//Act
HttpResponseMessage response = await httpClient.GetAsync("http://localhost");

//Assert
response.StatusCode.Should().Be(HttpStatusCode.OK);
  1. Line #1 is how we create the test server. The Startup class is the class that defines your OWIN application.
  2. Line #2 is how we create the HttpClient that is internally configured to invoke your OWIN app's root application delegate.
  3. Line #3 & #4 is how we invoke and assert our application. (The assertion here uses the excellent FluentAssertions library).

And that's it! Fast, in-memory, CI friendly OWIN testing :)

A note on Owin.Testing history - I originally started this based of code from Gate. Later, Microsoft.Owin.Testing appeared which is similar, but has since been delisted. I have used some of the code from that. As far as I know at this point, there are no plans to revive Microsoft.Owin.Testing. So for the time being, I'll be continuing to maintain this.

Introducing Owin.SiteMapping

Owin.SiteMapping (nuget, github) is an OWIN middleware analgous to IIS's site mapping. That is, it allows you to partition your OWIN app according to host header, http scheme and port number.

Sometimes an example is best:

public class Startup
{
  public void Configuration(IAppBuilder builder)
  {
    builder
      .MapSite(new SiteMap("www.example.com"), main => main.Use(...))
      .MapSite(new SiteMap("admin.example.com", HttpScheme.Https, 443), admin => admin.Use(...));
  }
}

Here, all requests with host header 'www.example.com', regardless of http scheme or port will be routed down the 'main' OWIN branch. Whereas all requests for 'admin.example.com', only on Https and port 443, will be routed down the admin branch.

 

Bug reports, suggestions and contributions welcome.

Introducing Owin.EmbeddedResources

Update: this post is out of date. The core functionality has been imported into  Microsoft.Owin.StaticFiles. I've de-listed the Owin.EmbeddedResources package.

This library contains an implementation of IFileSystem which is a file system abstraction used by Microsoft.Owin.StaticFiles - a OWIN middleware for serving static content, directory browsing etc. (It isn't available on nuget.org yet, pending security review. It can be obtained from katana CI feed for now).

How to use.

1. Embed your static content as a resource: 

2a. In your OWIN Startup class, specify the IFileSystem implementation, EmbeddedResourceFileSystem:

public class Startup
{
  public void Configuration(IAppBuilder builder)
  {
    builder.UseStaticFiles(config => config.WithFileSystem(new EmbeddedResourceFileSystem())));
  }
}

This will default to using the calling assembly as the source of the embedded content.

2b. If your resources are in a different assembly you can specify the assembly in the EmbeddedResourceFileSystem constuctor:

public class Startup
{
  public void Configuration(IAppBuilder builder)
  {
    builder.UseStaticFiles(config => config.WithFileSystem(new EmbeddedResourceFileSystem(typeof(Foo).Assembly)));
  }
}

The Static files middleware has full support for generating etags and response content types based on extensions.

Notes

Embedded resources lose their folder structure when compiled in. For instance, embedding Resources\Area\Foo.bar will become Resources.Area.Foo.Bar, and embedding Resources\Area.Foo.Bar will also become Resources.Area.Foo.Bar. (Trying to do this with two files won't compile). Due to this non-transitive nature, it is not possible infer the directory from whence an embedded resource originally came from. Thus, directory browsing is not supported in this IFileSystem implementation.

Owin.HttpMessageHandler is now portable

As of version 0.3, Owin.HttpMessageHandler (nuget.org, github) is now shipped as portable class library supporting .NET 4.0 and later, Silverlight 4.0 and later, Windows 8.0 and WindowsPhone 7.1. The ability to customize the owin environment before and after handling the request has been added as well as better support for http 1.1 that requires a host header.

A word NEventStore concurrency

NEventStore implements optomistic concurrency for Commits based on the StreamId and CommitSequence (and BucketId in v5). The exact implementation of which depends on the persistence engine. For instance, for SQL storage engines it is enforced by a primary key. This means if you open the same stream twice concurrently, add a commit, and close, you will get a ConcurrencyException:

IStoreEvents store = Wireup
	.Init()
	.UsingInMemoryPersistence()
	.Build();

Guid streamId = Guid.NewGuid();
using (var stream1 = store.OpenStream(streamId, 0, int.MaxValue))
using (var stream2 = store.OpenStream(streamId, 0, int.MaxValue))
{
	stream1.Add(new EventMessage{ Body = "test"});
	stream2.Add(new EventMessage{ Body = "test"});
	stream1.CommitChanges(Guid.NewGuid());
	stream2.CommitChanges(Guid.NewGuid()); // throws ConcurrencyException
}