Tag Archives: Testing

Unit Testing MVC Controllers

If you use the ASP.NET MVC Extension with ASP.NET MVC 4, you may encounter problems running unit tests if you inherit from the MicroLiteController or MicroLiteReadOnlyController.

This is because the MVC Extension for MicroLite is currently built against ASP.NET MVC 3.

Since the Controller classes in ASP.NET MVC 4 are backwards compatible with MVC 3, you can fix this by adding an app.config to your unit test project with a binding redirect for ASP.NET MVC as follows:

<runtime>
  <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
    <dependentAssembly>
      <assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" />
      <bindingRedirect oldVersion="0.0.0.0-4.0.0.0" newVersion="4.0.0.0" />
    </dependentAssembly>
  </assemblyBinding>
</runtime>
Advertisements

Unit Testing when using the Convention Based Mapping

If you are using the new Convention Based Mapping introduced in MicroLite 3.0 and want to unit test code which uses the SqlBuilder, you will need to ensure that the convention extension is loaded before the tests are run.

The reason for this is that the SqlBuilder reads the ObjectInfo for the type being queried to append the column names and ObjectInfo uses the mapping convention to interrogate the type information. Since the default mapping convention is the AttributeMappingConvention, it will be called instead of the ConventionMappingConvention.

The recommended approach here is to move the configuration of MicroLite extensions into a separate class:

public static class MicroLiteConfig
{
    public static void ConfigureExtensions()
    {
        Configure
            .Extensions()
            .WithNLog() // If used, always load the logging extension first.
            .WithConventionBasedMapping(new ConventionMappingSettings
            {
                IdentifierStrategy = IdentifierStrategy.DbGenerated,
                UsePluralClassNameForTableName = true
            })
            .WithMvc();

        // Register any listeners etc.
    }
}

You can then call MicroLiteConfig.ConfigureExtensions() in your test setup method.

This article was written for version 3.0.0 of the MicroLite framework.

Unit Testing classes which use ISession

One of the original principles behind MicroLite was that it should be easy to write tests for code which uses it. Therefore, a lot of thought has gone into the architecture of the API to make sure that it is well abstracted.

Lets take a simple class which processes an order for a customer:

public class OrderProcessor
{
    private ISession session;

    public OrderProcessor(ISession session)
    {
        this.session = session;
    }

    public void ProcessOrder(int orderId, int customerId)
    {
        // Use an include for the customer so we don't do 2 database calls.
        var includeCustomer = this.session.Include.Single<Customer>(customerId);
        var order = this.session.Single<Order>(orderId);
        var customer = includeCustomer.Value;

        // Process the order.
        // ...

        order.Processed = DateTime.Now;

        this.session.Update(order);
    }
}

Note: Although transactions have not been used in this example for brevity, they should be used in all production code!

And an example unit test (using NUnit and Moq):

[Test]
public void ProcessOrderUpdatesProcessedDateAndSavesOrder()
{
    // Use the Moq framework to create an ISession which we can configure to behave in a specific way.
    var mockSession = new Mock<ISession>();

    // Set up the customer id & a customer instance.
    var customerId = 1345;
    var customer = new Customer();

    // Set up the mock session to return the customer.
    // By using the helper class in MicroLite.Testing, we save having to create a pretend implementation of IInclude<T>.
    mockSession
        .Setup(s => s.Include.Single<Customer>(customerId))
        .Returns(Include.Single(customer));

    // Set up the order id & order instance.
    var orderId = 73578;
    var order = new Order();

    // Since we are returning the order via the standard interface (not as an include) we don't need to do anything special with it.
    mockSession.Setup(s => s.Single<Order>(orderId)).Returns(order);

    // Set up the update method so we can check it was called.
    mockSession.Setup(s => s.Update(order));

    // Create an order processor, supplying it with the mocked ISession implementation with the behaviour we set up above.
    var orderProcessor = new OrderProcessor(mockSession.Object);

    // Call the method that we actually want to test.
    orderProcessor.ProcessOrder(orderId, customerId);

    // Check that all the methods on the mock session which we were expecting to be called were called.
    mockSession.VerifyAll();

    // Lastly, check that the processed property has been set.
    Assert.GreaterOrEqual(order.Processed, DateTime.Now.AddSeconds(-1));
}

Hopefully this gives you an idea of how you can architect your code which uses MicroLite to take advantage of the testability of the framework.

This article was written for version 2.0.0 of the MicroLite framework and version 1.0.0 of the MicroLite.Testing package.

MicroLite.Testing 1.0 released

The new Includes feature in MicroLite 2.0 has made it easier to reduce your data access footprint by batching multiple database queries into a single call to load all the data you need in one go. This however has had a slight negative impact on the simplicity of testing code which uses MicroLite, this is because the include methods return interfaces rather than objects (in the way that Single, Fetch and Paged do).

Now, since interfaces are being returned, it is still possible to test the methods by creating mocks of the interface which leads to code such as this:

var mockInclude = new Mock<IInclude<Customer>>();
mockInclude.Setup(i => i.Value).Returns(customer);

mockSession
    .Setup(s => s.Include.Single<Customer>(customerId))
    .Returns(mockInclude.Object);

While this works, we can do better (imagine if you were including 3 or 4 object in the method you are testing!).

Therefore, a new project has been released – MicroLite.Testing. The initial release has some classes to make testing includes easier.

If we install the MicroLite.Testing package and add a using MicroLite.Testing; to our test class, we no longer have to mock the include interfaces and can do this instead:

mockSession
    .Setup(s => s.Include.Single<Customer>(customerId))
    .Returns(Include.Single(customer));

Much better 🙂

There are 4 methods on the MicroLite.Testing.Include class:

  • Many<T>() – This method will return an Include many which contains no values to simulate no results for an include.
  • Many<T>(IList<T> values) – This method will return an Include many which contains the specified values to simulate results being returned.
  • Single<T>() – This method will return an Include with the default value of T (null for a reference type, 0 for an integer etc) to simulate no results for the include.
  • Single<T>(T value) – This method will return an Include with the specified value to simulate a single result being included.

This article was written for version 2.0.0 of the MicroLite framework and version 1.0.0 of the MicroLite.Testing package.