Ruthlessly Helpful

Stephen Ritchie's offerings of ruthlessly helpful .NET practices.

Four Ways to Fake Time, Part 4

The is the fourth and final part in the Four Ways to Fake Time series. In Part 3 you learned how to use the IClock interface to improve testability. Using the IClock interface is very effective for new application development. However, when maintaining a legacy system adding a new parameter to a class constructor might be a strict no-no.

This part looks at how a mock isolation framework can help. The goal of isolation testing is to test the code-under-test in a way that is separate from dependencies and any underlying components or subsystems. This post looks at how to fake time using the product TypeMock Isolator.

Fake Time 4: Mock Isolation Framework

The primary benefit of a mock isolation framework is that no refactoring of the code-under-test is needed. In other words, you can test legacy code as it is, without having to improve its testability before writing maintainable test code. Here is the code-under-test:

using System;
using Lender.Slos.Utilities.Configuration;

namespace Lender.Slos.Financial
{
    public class ModificationWindow
    {
        private readonly IModificationWindowSettings _settings;

        public ModificationWindow(
            IModificationWindowSettings settings)
        {
            _settings = settings;
        }

        public bool Allowed()
        {
            var now = DateTime.Now;

            // Start date's month & day come from settings
            var startDate = new DateTime(
                now.Year, 
                _settings.StartMonth, 
                _settings.StartDay);

            // End date is 1 month after the start date
            var endDate = startDate.AddMonths(1);

            if (now >= startDate && 
                now < endDate)
            {
                return true;
            }

            return false;
        }
    }
}

With TypeMock, the magic happens in two ways. First, the test method arrangement uses the Isolate class to setup expectations. The test method sets up the DateTime.Now property so that it returns currentTime as its value. This fakes the Allowed method.
Here is the revised test code:

[TestCase(1)]
[TestCase(5)]
[TestCase(12)]
[Isolated] // This is a TypeMock attribute
public void Allowed_WhenCurrentDateIsInsideModificationWindow_ExpectTrue(
    int startMonth)
{
    // Arrange
    var settings = new Mock<IModificationWindowSettings>();
    settings
        .SetupGet(e => e.StartMonth)
        .Returns(startMonth);
    settings
        .SetupGet(e => e.StartDay)
        .Returns(1);

    var classUnderTest =
        new ModificationWindow(settings.Object);

    var currentTime = new DateTime(
        DateTime.Now.Year,
        startMonth,
        13);

    Isolate
        .WhenCalled(() => DateTime.Now)
        .WillReturn(currentTime); // Setup getter to return the test's clock

    // Act
    var result = classUnderTest.Allowed();

    // Assert
    Assert.AreEqual(true, result);
}

Second, the test must run in an isolated environment. This is how TypeMock fakes the behavior of System.DateTime; the test is running within the TypeMock environment. Here is the TypeMock Isolator configuration window.
TypeMock Isolator

The Cost of Isolation

Since TypeMock Isolator is a commercial product, be prepared to make the case for purchasing Typemock. Here is some information on the business case for TypeMock: http://www.typemock.com/typemock-newsletters/2011/3/7/typemock-newsletter-march-2011.html

I find that TypeMock Isolator 6.2.3.0 is well integrated with Visual Studio 2010 SP1, ReSharper 6.1 and dotCover 1.2.

In Chapter 2 of Pro .NET Best Practices, you learn about Microsoft Research and the Pex and Moles project. Moles is a Visual Studio power tool, and you will find the latest download through the Visual Studio Gallery. As I describe, the Moles framework allows Pex to test code in isolation so that Pex is able to automatically generate tests. Therefore, you can use Moles to write unit tests that fake time.

Moles, as a way to fake time, is described in the Channel 9 post Moles – Replace any .NET method with a delegate and the blog post Did you know Microsoft makes a mocking tool?.

Just like Code Contracts, I hope and expect that Microsoft will make Moles a more significant part of .NET and Visual Studio. Today, I don’t find that Moles offers the same level of integration (for now?) with ReSharper and dotCover that TypeMock has. When I use Moles, I run my test code within their isolation environment from the command line. It works, but I really do prefer using the ReSharper test runner.

To sum up the mock isolation framework approach:
Pros:

  • Works well when applied to legacy or Brownfield code
  • No impact on class-users and method-callers
  • A system-wide approach
  • Testability is greatly improved

Cons:

  • Tests must run within an isolation environment
  • Commercial isolation frameworks can be cost prohibitive

I hope you found this overview of four ways to fake time to be helpful. I certainly would appreciate hearing from you about any new, different, and hopefully better ways to fake time in coded testing.

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

%d bloggers like this: