Testing untestable code thanks to MS Fakes

Every developer who has coded unit tests (in an ideal world this should be every developer from every single line of code^^) has probably met some untestable code problems: bad software design, dependencies,… Art of software makes a great place to testability nowadays and editors have understood this and started to worry about testability of their components – Asp.Net MVC is a good example, it allows testing for almost everything very easily thanks to built in dependency injection. But we still have often to work on old code not designed to be testable. Fortunately, a new Visual Studio 2012 will help us to achieve this anyway.

MS Fakes allows us to generate fake objects from any assembly referenced in a test project. 2 types of objects are generated: Stub objects ans Shim objects. Stubs are made for every abstract classes and interfaces from the source assembly and allow to create instances of these classes. Testing these was already possible without MS Fakes but generation helps us in this time consuming task. But the most interesting are the Shim objects.

Those Shims create copies of all the classes from the source assembly, even those which were not extensible or not directly instanciable. We will show this feature through a very simple example. We’ll try to test this method:

public class SomeClass
{
    public bool SomeMethod()
    {
        var session = HttpContext.Current.Session;
        if (session["someSessionData"].ToString() == "OK")
            return true;
        return false;               
    }
}

The way this method is written makes it difficult to test because test context don’t have an HttpContext and even less session object with session data. Shims will allow us to test it anyway by redefining in the test context the call to HttpContext.Current and we will then be able to go back on the session object by redefining it also inside the fake HttpContext.

First thing to do is to generate the fake assembly. To do this, right click the System.Web reference and select “Add Fakes Assembly”

Avant tout, il faut générer l’assembly de fakes. Pour cela déroulez les références de votre projet de test, clic droit sur System.Web et sélectionnez System.Web

generate fake assembly

This “fake” assembly generated contains source assmbly namespaces with a .Fakes suffix. The method we want to test doesn’t take any argument et directly calls HttpContext.Current.Session so we will have to fake the HttpContext class, the Current static property, and the Session property.We will also have to simulate HttpSessionState object to give it a value to return in the session[“someSessionData”] call. Let’s consider the test passed if the method returns true. It will look like this:

[TestMethod]
public void SomeTestMethod()
{
    using (ShimsContext.Create())
    {
        var instanceToTest = new SomeClass();

        var session = new System.Web.SessionState.Fakes.ShimHttpSessionState();
        session.ItemGetString = (key) => { if (key == "someSessionData") return "OK"; return null; };

        var context = new System.Web.Fakes.ShimHttpContext();
        System.Web.Fakes.ShimHttpContext.CurrentGet = () => { return context; };
        System.Web.Fakes.ShimHttpContext.AllInstances.SessionGet =
            (o) =>
            {
                return session;
            };
        
        var result = instanceToTest.SomeMethod();
        Assert.IsTrue(result);
    }
}

We will need Shims so we begin by creating a ShimsContext. In the scope of this context, we will be able to intercept references to some classes to replace them with our fake objects. Then we instantiate a System.Web.SessionState.Fakes.ShimHttpSessionStat object which is a copy of the System.Web.SessionState on which we have all access for redefining methods and behaviors. Next line does this by redefining the get_Item(string) methos used by the indexer. MS Fakes creates by convention property ItemGetString = property name + Get or Set + type of the argument if there are overloads. This property is typed Func, it allows us to give it a new behavior via a lambda expression. Here, we will return the “OK” value if the key asked for is “someSessionData” and null otherwise.

In the rest of the test, we create the same way a ShimHttpContext instance and we redefine the static property Current to return this instance. Still the same way, we redefine the Session property of all HttpContext instances to return the ShimHttpSessionState created just before.

We now just have to call the method to tes and test it’s return value. During test execution, HttpContext and HttpSessionState instances are replaced by the Shim objects automatically et our new property and method implementations are called instead of the real object ones: the test succeeds.

On code not designed for testability, Shims give us interesting testing possibilities. Stubs, even if they are less interesting, are really time saving even on code designed for testability. Let’s test this simple method:

public class SomeClass
{
    public bool SomeMethodWithCustomInterface(ISomeInterface myInterface)
    {
        var result = myInterface.SomeInterfaceOperation();
        return result;
    }
}

ISomeInterface is as above:

public interface ISomeInterface
{
    bool SomeInterfaceOperation();
}

We will generate the fakes assembly the same way we did for System.Web but this time on the assembly which contains the interface. We can then see that a Stub object has been created: StubISomeInterface. We will easily be able to instanciate it and redefin it’s method to pass it to the method we want to test:

[TestMethod]
public void SomeTestMethodForCustomInterface()
{
    var instanceToTest = new SomeClass();

    var testInterfaceImplementation = new MsFakesExample.Fakes.StubISomeInterface();
    testInterfaceImplementation.SomeInterfaceOperation = () => { return true; };

    var result = instanceToTest.SomeMethodWithCustomInterface(testInterfaceImplementation);
    Assert.IsTrue(result);
}

The test succeeds again.

To be more complete on this article, you have to know that other frameworks allow us to do this kind of things from long time ago but this one is built in with Microsoft test framework and natively available in Visual Studio 2012.

The article code is available for download HERE
Nobody now has justification to bypass unit testing! (personal message for my team members whom will recognize theirselves :) )

Advertisements
This entry was posted in Visual Studio and tagged , , , , , , . Bookmark the permalink.

2 Responses to Testing untestable code thanks to MS Fakes

  1. Qamar says:

    Christopher thanks for posting this info. This was very helpful to me.

  2. Pingback: VS 2012 Fake DLLs für Tests (stubs und shims) | SquadWuschel's Blog

Answer

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