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.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s