Integration testing an ASP.Net MVC 5 web application that uses Structuremap

1/8/2016

Integration testing, it must've been several years ago that I first got to know the concept. Like unit testing, the benefits were and still are quite obvious. When developing I've found a good set of tools to do unit testing, but finding a set of tools to do integration testing has been a constant struggle. I tried using Selenium and WatiN. Creating the little tests with the recorder was pretty neat, but reality struck pretty fast when I experienced first hand how brittle UI integration tests really are. Change something in the UI? You can practically throw away your existing tests and start over. Because the tests were so brittle, the result was hardly usable and very time consuming. Tests were constantly failing just because something changed in the UI, not because there was a bug in the application. Maintaining a suite of UI integration tests was not an option.

In 2011 I attended Arrrrcamp and saw a talk, forgot by who, about integration testing with Capybara. I was impressed with the tool but unfortunately it could only be used for testing Ruby. And to my frustration the tooling for ASP.Net never really seemed to catch on, I've never found something similar to Capybara for Asp.Net. After this integration testing went off my radar, I had given up finding a decent tool. It was not until a few years later that I got interested again in integration testing, I read on Twitter that someone was doing integration testing but instead of doing UI integration testing, they used NUnit to test their classes directly. I was intrigued by the idea, the outcome are integration tests that can be run by a test runner (think TestDriven.Net, JetBrains Test runner, ...) like you would run a unit test. Pretty neat.

The project I used this on is an ASP.Net MVC 5 web application, but the principles can be applied to an ASP.Net core project although I've noticed that the syntax and configuration has changed quite a bit. The MVC project uses StructureMap to resolve dependencies, for this I used the StructureMap.MVC5 Nuget package which does the grunt work for you. The example is pretty simple, there is a HomeController which renders a view. In this HomeController a value is read from the database. This is our controller:

public class HomeController : Controller
{
    private readonly IDataRetriever _dataRetriever;

    public HomeController(IDataRetriever dataRetriever)
    {
        _dataRetriever = dataRetriever;
    }

    public ActionResult Index()
    {
        var data = _dataRetriever.Retrieve();
        return View((object) data);
    }
}

Nothing fancy, the controller has one dependency which retrieves the data from the database. The retrieved data is passed to the Index.cshtml view as its Model. I'm a big fan of Micro ORMS and hand-writing SQL, by the way just learn SQL, so I use Dapper to retrieve the data from the database and map it to an object, in this case a simple string.

public class DataRetriever : IDataRetriever
{
    private readonly IConfigurationRetriever _configRetriever;

    private IDbConnection GetConnection()
    {
        var connectionString = _configRetriever.ConnectionString;
        return new SqlConnection(connectionString);
    }

    public DataRetriever(IConfigurationRetriever configRetriever)
    {
        _configRetriever = configRetriever;
    }

    public string Retrieve()
    {
        var sql =
            @"select DataColumn
              from Dummy";

        var parameters = new {};

        using (var connection = GetConnection())
        {
            var result = connection.Query<String>(sql, parameters).ToList();
            return result.Any() ? result.First() : default(dynamic);
        }
    }
}

The DataRetriever class takes a ConfigurationRetriever dependency, which reads the connection string from the web.config. A new SqlConnection instance is created with the connection string found in the web.config. Then the data is read from the database, if there is a result then the first row is returned. I really like this way of retrieving data, tweaking the queries is easy and straightforward and everyone who knows sql can quickly make changes if necessary. The biggest disadvantage of this approach are the sql strings. If someone has fat fingers and accidentally inserts a character in these sql queries the application will crash when the code is called. No unit test will catch a typo in a string, or that would be a very brittle unit test and I don't write unit tests for this kind of code. This is the gap that integration tests can fill. In this particular case I just test the DataRetriever class with its dependencies but it's possible to test a more complex case with more dependencies or to do end-to-end testing. The code to do this is almost identical. This is the integration test:

[TestFixture]
public class When_retrieving_data
{
    [SetUp]
    public void SetUp()
    {
        var container = TestSetup.Setup();
        _classUnderTest = container.GetInstance<IDataRetriever>();
        _result = _classUnderTest.Retrieve();
    }

    [Test]
    public void Then_the_found_data_is_returned()
    {
        Assert.That(_result, Is.Not.Null);
    }

    private IDataRetriever _classUnderTest;
    private string _result;
}

The TestSetup class is a helper class which will set up a StructureMap container. We use the container to resolve the dependencies and create a DataRetriever instance. Then the method that we want to test is called and the result is verified. That's it. We now have an integration test which runs the query against the database and tests the result that is returned. This is the TestSetup class:

public class TestSetup
{
    public static IContainer Container { get; private set; }

    public static IContainer Setup()
    {
        Container = new Container();
        Container.Configure(init => init.AddRegistry<TestIocRegistry>());

        return Container;
    }
}

It creates a container and configures it with a StructureMap Registry specifically created for the integration tests.

public class TestIocRegistry : Registry
{
    public TestIocRegistry()
    {
        Scan(scanner =>
        {
            scanner.Assembly("AspNetMvcStructureMapIntegrationTesting");
            scanner.WithDefaultConventions();
            scanner.With(new ControllerConvention());
        });

        For<IConfigurationRetriever>().Use<FakeConfigurationRetriever>();
    }
}

The test registry is configured to scan for dependencies in the correct assembly with default conventions. The ControllerConvention class is provided by the StructureMap.MVC5 Nuget package and helps to create the ASP.Net MVC controllers. We fake out the ConfigurationRetriever because that is a dependency we do not have in our integration tests projects. The ConfigurationRetriever class retrieves the connection string from the web.config, our integration tests do not have a web.config so we create a fake that returns a hard coded connection string.

public class FakeConfigurationRetriever : IConfigurationRetriever
{
    public string ConnectionString => @"Data Source=.\SQLEXPRESS;Initial Catalog=integration_testing;Persist Security Info=True;User ID=sa;password=test;Pooling=false";
}

That is all. We now have a working integration test, if we add a character to the query which makes the call to the database fail and rerun our integration tests we will have a failing test.

Failed integration test

I can't find the time to fix the comments on my blog but if you have any questions or remarks feel free to tweet me.

The project with small test database can be found on github.