Working with the Microsoft Fakes framework in Visual Studio

Isolation of the dependencies in code by mocking or faking objects is one of the common norms when developing unit tests or creating a Test-driven development. People write mocking objects that can be used to redirect calls to some dependent objects in order to independently test modules. There are also a number of frameworks that generate mocking objects automatically based on the existing dependencies without having to use any handwritten objects. The Visual Studio 2013 Ultimate edition comes with a new Microsoft Fakes framework that takes mocking to a new level.

If you have used Microsoft Moles before, you will find that the Fakes framework has a very similar workflow. Moles was originally designed for Microsoft Pex, which is another great unit testing tool by Microsoft Research. Moles became popular because it could virtually create mocks on anything and was so simple that there was hardly any overhead on using it. Moles provided a type safe detour framework with very clear semantics. For example, any .NET method in Moles is represented by a delegate. Microsoft replaces Moles in Visual Studio 2013 with the Microsoft Fakes framework, with the working principles defined almost the same as it.

Microsoft Fakes uses stubs and shims to replace other parts of the dependencies while testing a unit. These are small pieces of code that are used in tests. Thus, replacing unnecessary dependencies using stubs and shims ensures that you find an appropriate cause of a test failure. Stubs and shims are helpful to test parts of the code that are still to be implemented.

  • Stubs: This replaces the call of one class with another class implementing a common interface. To use stubs, the design of the test method should always use an interface to call an object rather than calling the class directly. Typically, we use stubs for the components that are defined inside the same assembly.
  • Shims: This modifies the compiled code of the application at runtime replacing the original calls to some API with a shim code defined inside the test providers. Shims are slow and require runtime to rewrite the code during compilation.

In this recipe, we are going to create tests for the code that has external dependencies either from the .NET class library or from inside our own code.

Getting ready

Before going ahead, it would be a good idea to create code that can be tested using the Microsoft Fakes framework. The following static method checks whether the current date is December 21, 2012, and based on this, it will throw an exception:

public static void DoomsDay()
{
    if(DateTime.Now.Equals(new DateTime(2012, 12, 21)))
        throw new Exception("Time's Up !!!! World will end now");

    //Other code
}

You can see that it is as a static method but it has the DateTime.Now static property tied to it, which makes it very hard to test the method and generate an exception. As the DateTime.Now property is defined inside the .NET framework and will evaluate DoomsDay only when the system date reaches that particular day, it will become mandatory to replace the call with some fake calls:

public static void DeleteTemporaryData(string dirLocation)
{
    Directory.Delete(dirLocation, true);
}

Similar to the preceding code, DeleteTemporaryData will delete the entire directory that has been passed recursively.

We will create an interface ILogger to implement the Logger utility. To test the stubs, we will call the interface to create an external dependency:

public string GetEventName(ILogger logger)
{
    if (logger.IsLoggerEnabled)
        logger.Log("GetEventName method is called");

    return "Sample Event";
}

Here, the ILogger interface has one Boolean property IsLoggerEnabled and a Log method to write the log entry from the logger.

How to do it...

Let's take a look at how we can create a Fakes project solution in the following steps:

  1. Add a new unit test project to the solution and name it MSFakesSample.Tests.
  2. Get rid of the default file and create a test unit.
  3. Add a reference to the class library that we need to test the test project. To enable Fakes types for an assembly, go to the Solution Explorer pane, open References, right-click on the assembly that you want to Fake, and select Add Fakes Assembly. This will automatically create a Fake assembly with all the additional features to call it just like a normal one. It is necessary to create a Fake assembly for System.dll. We can right-click on the normal assembly to create its Fake, as shown in the following screenshot:
    How to do it...
  4. Once the Fake assembly is created, let's test the DoomsDay method we created earlier. As a test case, we need to generate an exception, which is only intended for December 21, 2012. We use shims to define a Fake implementation of DateTime.Now inside ShimsContext:
    [TestMethod]
    [ExpectedException(typeof(Exception))]
    public void DoomsDay_Test_Shims()
    {
        using (ShimsContext.Create())
        {
            ShimDateTime.NowGet = () => new DateTime(2012, 12, 21);
            DiagonizeShims.DoomsDay();
        }
    }

    In the preceding unit test, the Fakes assembly for the project automatically creates intercepts that can redefine the existing APIs. Here, inside ShimsContext we redefine the Get method of the property. Now using Delegate, which returns a valid date, a call to the DoomsDay method generates the expected exception.

  5. Notice that DateTime.Now is defined in mscorlib.dll, which has been faked using the Fakes framework. You can also specify BehaveAsNotImplemented to ensure that an API throws NotImplementedException when it is called:
    [TestMethod]
    [ExpectedException(typeof(ShimNotImplementedException))]
    public void DeleteDirectory_BehaveNotImplemented()
    {
        using (ShimsContext.Create())
        {
            ShimDirectory.BehaveAsNotImplemented();
            DiagonizeShims.DeleteTemporaryData(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData));
        }
    }

    In the preceding code, DeleteTemporaryData generates ShimNotImplementedException because we defined the Fakes implementation of the Directory class to BehaveAsNotImplemented. Remember that the shims implementation will only work on the calls inside ShimsContext.

  6. Unlike shims, stubs on the other hand are used to fake virtual types, such as interfaces, abstract classes, and virtual methods. Stubs cannot be used in a nonvirtual context, such as private, sealed, or static types. To write a unit test for the GetEventName method, we use a stub for the ILogger interface so that it does not actually log data, rather it calls the custom test logger stubs:
    [TestMethod]
    public void GetEventName_Test()
    {
        //Arrange
        var sLogger = new StubILogger
        {
            IsLoggerEnabledGet = () => true
        };
        var sut = new DiagonizeStubs();
        //Act
        var result = sut.GetEventName(sLogger);
    
        //Assert
        Assert.IsFalse(string.IsNullOrEmpty(result));
    }

    In the preceding code, the test will call StubILogger, which is a fake implementation of the ILogger interface and is used instead of the actual Logger class. The StubILogger variable exposes properties that enable the tester to assign a delegate for the Get and Set methods of the properties and other methods associated with the interface. Here, we have changed the default implementation of the Get method of IsLoggerEnabled to return the true value.

  7. Stubs can also be associated with an observer. An observer allows you to record calls on stubs. The Fakes framework ships its own observer, which allows you to record every call and argument made in the stub just like any other standard isolation framework. Thus, we can rewrite the preceding test with an observer like the following one:
    [TestMethod]
    public void GetEventName_Test_Fakes()
    {
        //arrange 
        var stubLogger = new StubILogger { IsLoggerEnabledGet = () => true };
        var diagonizeStub = new DiagonizeStubs();
        var observer = new StubObserver();
        stubLogger.InstanceObserver = observer;
    
        //act
        diagonizeStub.GetEventName(stubLogger);
        var calls = observer.GetCalls();
                
        //assert
        Assert.IsNotNull(calls);
        Assert.AreEqual(2, calls.Length);
    }

    Here, we have created an instance of StubObserver, which is assigned to InstanceObserver for the logger implementation. If you remember the actual definition of GetEventName, it first checks the value of IsLoggerEnabled before calling Log. The preceding code will observe two calls: one to the IsLoggerEnabledGet method and another to the LogString method.

  8. Finally, if we run all the tests, they will pass. This indicates that the stubs and shims actually injected Fake code to isolate dependencies in the application.

How it works...

The Microsoft Fakes framework provides a superior technique to isolate a portion of the code from external sources. Shims and stubs are important picks to implement the level of isolation. Shims are used mainly to test the untestable code that comes with calls from third-party components with a lot of statics and privates. Shims rewrite the code completely during compilation to replace the actual calls during testing, and hence it requires a long time to load. Stubs, on the other hand, are recommended for virtual types, which are much faster with minimum or no code replacement during compile time.

In the following diagram of the component, the test uses the component that has the dependency of some external files (System.dll) and some other components defined in the assembly. When an isolation technique is taken, the component replaces the calls to the external components with shim methods and other internal calls, using stubs.

How it works...

Shim replaces all the calls to a method inside its context with a new implementation, if provided. For instance, if you take a closer look at the implementation of ShimDateTime.NowGet in the preceding assembly using .NET Reflector, you will find that ShimRunTime replaces DateTime. The NowGet property with the delegate that we have passed data to the TestMethod is shown in the following code:

public static FakesDelegates.Func<DateTime> NowGet
{
    [ShimMethod("get_Now", 24)] 
    set
    {
        ShimRuntime.SetShimPublicStatic((Delegate) value, typeof(DateTime),      get_Now", typeof(DateTime), new Type[0]);
    }
}

In the preceding implementation of NowGet, you can see that the delegate we passed to the property is replaced with the actual get_Now method of the DateTime object only within the current context. On the other hand, calling the BehaveAsNotImplemented() method injects NotImplementedException inside the actual definition of the methods that are defined in the Directory class present inside the context. Thus, shims ensure that calls to any API are properly replaced to call a Fake assembly rather than the actual API call.

Unlike shims, stubs implement interfaces inside the Fake assembly. It ensures that all the methods (even the Get and Set methods of property) expose a matching property of the delegate type to enable the test environment to replace the default content when required. Shims also make calls to the observer to ensure that all the calls to the methods and properties are logged on the observer. If we see the implementation of StubILogger, we can also see that there are delegates defined for each of the three methods as follows:

    public FakesDelegates.Func<bool> IsLoggerEnabledGet;
    public FakesDelegates.Action<bool> IsLoggerEnabledSetBoolean;
    public FakesDelegates.Action<string> LogString;

The delegates passed to these methods will be called when the actual methods are called from the test environment.

See also

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.226.165.70