SpecsFor.Mvc gives you a lot in a single NuGet package.  You get a test web host, a strongly-typed API for navigating around and interacting with your MVC app, and standard hooks for dealing with cross-cutting concerns like authentication, but you also get hooks that you can use to add your own behavior.  In this post, I’ll show you how to use one of those hooks to load seed data into your application to facilitate testing.

[more]

The “Using SpecsFor.Mvc” Series

Seed Data?  What’s That?

Most applications require some initial data in order to function.  Maybe it’s an initial admin account, or a set of default product categories, but most apps have at least some data that needs to be present.  Beyond that, in order to create useful tests you will typically want some additional base data in your application.  For an eCommerce application, perhaps it’s some dummy products and dummy orders.  There’s also the issue of shared state.  In end-to-end integration tests, such as those that you can create with SpecsFor.Mvc, your tests will share a single database.  That means any changes a test makes to the database are going to be visible to all your other tests.  Shared state is something you typically want to avoid in tests since it can lead to cascading test failures and maintenance difficulties.  SpecsFor.Mvc enables you to load seed data into your app to establish an initial context and to reset that context after each spec is executed. 

Composing Configuration

There are several ways you could install seed data using SpecsFor.Mvc, but the way I’m going to show you utilizes a feature that I haven’t shown yet: configuration composition.  In all the examples I’ve shown so far, I’ve created a single SpecsForMvcConfig class to hold all of the configuration data for my test project.  SpecsFor.Mvc actually allows you to create multiple instances of SpecsForMvcConfig and to compose them together to create a final configuration.  This is useful for situations where you need to mutate your configuration depending on environment (such as when running on a build server, for example) or when you just want to separate your config to keep things clean.  Here’s what the SpecsFor.Mvc config looks like for one of my mobile web apps:

[SetUpFixture]
public class AssemblyStartup
{
    private SpecsForIntegrationHost _integrationHost;

    [SetUp]
    public void SetupTestRun()
    {
        var config = new SpecsForMvcConfig();
        config.Use<CommonConfig>();
        config.Use<SeedDataConfig>();

        _integrationHost = new SpecsForIntegrationHost(config);
        _integrationHost.Start();
    }

    [TearDown]
    public void TearDownTestRun()
    {
        _integrationHost.Shutdown();
    }
}

Loading Seed Data with NHibernate

We’ll leverage the ability to separate configuration data in SpecsFor.Mvc to create a SeedData config class.  The class needs to reset the database to an initial, known state before each spec is executed.  The (poorly-named, in hindsight) BeforeEachTest hook enables you to do exactly that.  Here’s the seed data config from the same mobile app referenced above:

public class SeedDataConfig : SpecsForMvcConfig
{
    public SeedDataConfig()
    {
        var bootstrapper = new NHibernateBootstrapperWrapper();
        bootstrapper.Execute();

        BeforeEachTest(() =>
                        {
                            //Wipe out the existing data.
                            NHibernateBootstrapper.CreateSchema();

                            using (var session = NHibernateBootstrapper.GetSession())
                            {
                                var user = User.CreateNewUser("[email protected]", "ThisIsADummyUser");
                                session.Save(user);

                                var customer = new Customer {Name = "Wal-Mart"};
                                var location = new Location {Description = "Cookeville"};
                                customer.AddLocation(location);
                                session.Save(customer);

                                var invoice = new Invoice
                                                {
                                                    //SNIP: Lots of property assignments
                                                };

                                session.Save(invoice);

                                session.Flush();
                            }
                        });
    }
}

It uses a utility method on my NHibernateBootstrapper to recreate the schema, then it creates a dummy user as well as a dummy customer, location, and an invoice.  This gives each spec one of each entity to work with as a starting point.  Each spec is also free to add additional seed data without having to worry about cleaning it up afterwards since the database is being nuked and recreated.

Configuring seed data through NHibernate is only one approach.  If your application has a domain or service layer, you could (and indeed most likely should) utilize this layer to build up context.  That approach has the advantage of being less-coupled to the underlying data model as well as exercising your domain and/or service layer as part of your tests. 

What’s next?

We’re nearing the end of basic topics, at least until version 2.0 ships, but I’ll cover two more very useful and interesting features next time: testing E-mail functionality and leveraging Web.config transforms.