SJCNet

SJCNet is the home of architect/developer/techie, Simon Coope.

Microsoft Fakes - Shims and Stubs

Overview

While revising for a recent Microsoft exam I've come across the Microsoft Fakes Framework. I'd not been aware of this before, but surprisingly it's been available since Visual Studio 11 (and potentially earlier).

The Microsoft Fakes framework is a mocking tool that's built into Visual Studio. At present it's only available in Premium and Ultimate editions.

The Fakes framework helps you to isolate code that you're trying to test by replacing or mocking pieces of the application with stubs or shims.

The following post will run through what stubs and shims are in greater detail and show a simple example of their use.

Note: I'm going to assume some understanding of testing and mocking of .NET code. So I won't be defining what Mocks are or how to set-up tests, etc.

Stubs

A stub is essentially a mock, which is a piece of code that replaces a publically accessible method on the object being mocked. This enables us to control how the mocked member responds thereby ensuring consistency in the tests.

To use stubs you have to ensure your code utilises interfaces to refer to dependent objects within the application. This is generally good design practice as it enables decoupling of dependencies, but to use mocks we're forced down this path.

MSDN defines a stub as follows:

A stub replaces a class with a small substitute that implements the same interface. To use stubs, you have to design your application so that each component depends only on interfaces, and not on other components.

Shims

Shims are different to Stubs in that they modify the compiled code to replace a specified method call with your own code. Shims are particularly useful to replace calls to third-party assemblies that you can't modify. They also allow us to test code that may not have been written in a way that's amenable to testing (e.g code not using dependency injection and other patterns that make testing easier).

MSDN defines a shim as follows:

A shim modifies the compiled code of your application at run time so that instead of making a specified method call, it runs the shim code that your test provides. Shims can be used to replace calls to assemblies that you cannot modify, such .NET assemblies.

Examples

As an example I've created a very basic reminder system. The system works by creating a reminder at set intervals (day, week, month). If the user misses the first reminder, the next interval us used. For example, if the 1 day reminder is missed a reminder for 1 week is raised.

Not a strictly real-world scenario I know. But useful to show testing using Shims and Stubs.

Sample Code

In my sample I have the following classes:

Reminder

This class represents the reminder that's generated.

public class Reminder
{
    public DateTime? Date { get; set; }
    public ReminderIntervals Interval { get; set; }
}

ReminderIntervals

This is an enum used to represent the available reminder intervals.

public enum ReminderIntervals
{
    None,
    Day,
    Week,
    Month
}

ReminderManager

This class is used to generate reminders depending on the current interval. The GenerateReminder method takes in the current interval and generates the next interval in the sequence (along with a date the reminder expires). To calculate this date the ReminderManager uses the DateCalculator object (shown next).

public class ReminderManager : IReminderManager
{
    private IDateCalculator _dateCalculator;

    public ReminderManager(IDateCalculator dateCalculator)
    {
        _dateCalculator = dateCalculator;
    }

    public ReminderManager()
    {
        _dateCalculator = new DateCalculator();
    }

    public Reminder GenerateReminder(int currentInterval)
    {
        return GenerateReminder((ReminderIntervals)currentInterval);
    }

    public Reminder GenerateReminder(ReminderIntervals currentInterval)
    {
        var result = new Reminder { Interval = ReminderIntervals.None };

        // Check if we're already at the max interval
        if (currentInterval == ReminderIntervals.Month) { return result; }

        // Calculate the next interval
        result.Interval = (ReminderIntervals)(currentInterval + 1);

        switch(result.Interval)
        {
            case ReminderIntervals.Day:
                result.Date = _dateCalculator.AddDays(1);
                break;
            case ReminderIntervals.Week:
                result.Date = _dateCalculator.AddWeeks(1);
                break;
            case ReminderIntervals.Month:
                result.Date = _dateCalculator.AddMonths(1);
                break;
        }

        return result;
    }
}

DateCalculator

The DateCalculator object adds days, weeks and months to the DateCalculator.CurrentDate value. Note that the CurrentDate value is read from DateTime.Now.

public class DateCalculator : IDateCalculator
{
    private DateTime CurrentDate
    {
        get { return DateTime.Now; }
    }

    public DateTime AddDays(int days)
    {
        return CurrentDate.AddDays(days);
    }

    public DateTime AddWeeks(int weeks)
    {
        return CurrentDate.AddDays((weeks * 7));
    }

    public DateTime AddMonths(int months)
    {
        return CurrentDate.AddMonths(months);
    }
}

Tests

To create stubs and shims, first we have to create a fakes assembly. We do this by right-clicking on the assembly you want to 'fake' (in my case the assembly is called SJCNet.Samples.MicrosoftFakes.Domain) and selecting 'Add Fakes Assembly'.

![Add Fakes Assembly Menu](/content/images/2015/01/MSFakesAddFakesAssembly.jpg)

After completing this step you'll notice a few additions to your test project:

![Fakes Assemblies](/content/images/2015/01/MSFakesAssemblyList.jpg)

Here we see the base Fakes assembly (Microsoft.QualityTools.Testing.Fakes) has been added. But in addition to that a fake assembly has been created for the assembly under test (called SJCNet.Samples.MicrosoftFakes.Domain.Fakes), note the postfix of `.Fakes`.

Further to this if you compile the project and view the "obj/debug" folder you'll see a fakes folder. This folder contains the decompiled code of our assembly under test. It's in a Visual Studio project, so you can run the '.csproj' file to see the generated code.

Now to write some tests...

Stub Test

The following test uses a stub to replace the dependency the ReminderManager has on the DateCalculator. The stub is generated based on the IDateCalculator interface and configures the DateCalculator.AddDays method to return a DateTime that's calculated from an expected date value.

public void GenerateReminder_WithCurrentIntervalOfNone_ShouldReturnNextExpiryOfDay()
{
    // Arrange - Mock date calculator
    var dateCalculator = new StubIDateCalculator()
    {
        AddDaysInt32 = (input) => { return DateTime.Parse("01 Jan 2014 13:00:00").AddDays(input); }
    };

    // Arrange - Set-up reminder manager
    var reminderMgr = new ReminderManager(dateCalculator);

    // Act
    var reminder = reminderMgr.GenerateReminder(ReminderIntervals.None);

    // Assert - reminder and reminder date should not be null
    Assert.IsNotNull(reminder);
    Assert.IsNotNull(reminder.Date);
            
    // Assert - Should return next interval of day
    Assert.AreEqual(ReminderIntervals.Day, reminder.Interval);

    // Assert - Should return a day from start date
    Assert.AreEqual(_startDate.AddDays(1), reminder.Date);
}

The above test passes because we mocked and injected the DateCalculator into the ReminderManager, meaning we were able to consistently control the output from the DateCalculator object to test the ReminderManager.GenerateReminder method.

Shim Test

Now we're going to test for DateCalculator.AddDays method. As you can see from the sample code above the AddDays method just adds the days parameter to the CurrentDate property. The CurrentDate property is just an alias for the System.DateTime.Now property.

So to test the AddDays method we need to consistently control the output from the CurrentDate property. To do this we can use a shim.

public void AddDays_Add3_CorrectDateReturned()
{
    using (ShimsContext.Create())
    {
        // Arrange - Set-up date calculator
        var currentDate = DateTime.Parse("01 Jan 2014");
        Domain.Fakes.ShimDateCalculator.AllInstances.CurrentDateGet = 
                    (instance) 
                    => { return DateTime.Parse("01 Jan 2014"); };

        // Arrange - Create the date calculator
        var dateCalc = new DateCalculator();

        // Act - Add days
        var actualDate = dateCalc.AddDays(3);

        // Assert - Check the returned date
        Assert.AreEqual(currentDate.AddDays(3), actualDate);
    }
                
}

The first thing to note in the above example is that to use shims we have to create a ShimsContext. This is the context that the shim operates in, outside of this context the DateCalculator.CurrentDate property returns the System.DateTime.Now value and not our shim value. Once we create the shim inside the ShimsContext we can instantiate the DateCalculator as normal and execute the test.

We also use the AllInstances member in the creation of the shim. This means (as implied) that all instances of the DateCalculator created in the ShimsContext will return the shimmed value. Also, this means that all shim functions are passed the instance of the object being shimmed (see the instance parameter in the creation of the shim above).

Finally, it's also important to note we are shimming a private property! Pretty cool and useful...

Additionally, we could refactor the DateCalculator class as follows:

public class DateCalculator : IDateCalculator
{
    public DateTime AddDays(int days)
    {
        return DateTime.Now.AddDays(days);
    }

    public DateTime AddWeeks(int weeks)
    {
        return DateTime.Now.AddDays((weeks * 7));
    }

    public DateTime AddMonths(int months)
    {
        return DateTime.Now.AddMonths(months);
    }
}

Above we've removed the CurrentDate property and are using the DateTime.Now value in the methods. To test this we would need to do something pretty cool... We can create a fake of the System assembly and shim the response from DateTime.Now. To do this we'd add a fakes assembly as illustrated above. Then we'd write a test a follows:

public void AddDays_Add3_CorrectDateReturned()
{
    // Arrange - Shim DateTime.Now
    using (ShimsContext.Create())
    {
        // Set-up the shim
        var currentDate = DateTime.Parse("01 Jan 2014");
        ShimDateTime.NowGet = () => currentDate;

        // Arrange - Create the date calculator
        var dateCalc = new DateCalculator();

        // Act - Add days
        var actualDate = dateCalc.AddDays(3);

        // Assert - Check the returned date
        Assert.AreEqual(currentDate.AddDays(3), actualDate);
    }
}

In the above test we shim the System.DateTime.Now property to return our currentDate variable. Now we can test the DateCalculator without shiming the class under test.

Other Considerations

Some other things to consider when using the Microsoft Fakes framework.

  • Performance - Shims don't perform as well as stubs because shims have to rewrite code. But tests shouldn't take too long to run anyway... right?

  • Visual Studio Support - As previously mentioned the Microsoft Fakes functionality is only available in Visual Studio Premium and Ultimate. At the time of writing I can't find anything to suggest this is going to change.

Wrap Up

This has been a quick overview of the Microsoft Fakes framework and examples using shims and stubs.

Please let me know if anyone has any questions or comments...

Author image
About Simon Coope
Sydney, Australia Website
Experienced developer/consultant. Loves all things development, technology, gadgets, football and running.