Shim constructors to isolate “Future Objects”

I’ve already blogged previously about the new Shim Library of Visual Studio 2012

Now it is time to explore another scenario where shim can save your life. Suppose you are working with Hardware, Es. a barcode reader and you have a class in your system wrote in this way.

public class BarcodeReader
{
    public BarcodeReader() { 
        //connect to the hardware, if the hardware is not there 
        //throw an exception
    }

    public String ReadCode() 
    {
        //dialogate with the hardware and get the Barcode
    }
}

This class manage the connection to a physical BarcodeReader in the constructor and if something went wrong throws an exception and expose a ReadCode method that ask the Physical reader to read a Barcode. This class is used with the following pattern throughout all the software.

public class MyLogic
{
    private BarcodeReader reader;

    public MyLogic() {
        reader = new BarcodeReader();
    }

    public String RetrieveIndustrialCode()
    {
        String rawCode = reader.ReadCode();
        return rawCode.Substring(2, 10);
    }
}

MyLogic is a class with some business logic based on the Barcode returned from the call to ReadCode() method, as you can see it simply instantiate an instance of BarcodeReader in the constructor and read the code in the RetrieveIndustrialCode Method used to extract the industrial code from the raw content of the barcode. In this stupid example the algorithm to extract the Industrial Code from the Raw barcode read from the reader is simply reading chars from 2 to 10, but in real scenario we could have complex string parsing code that needs to be tested, but how?? As you can see from the code you can test only when the real hardware is connected to the machine because if a physical reader is not connected the BarcodeReader will throw exception, but the most annoying part is that it is impossible to simulate a read during a Unit Test.

This is another scenario where shims comes to the rescue, just add a fakes assembly (as described in the previous samples) and you can write this test.

[Fact]
public void verify_retrieval_of_industrialCode()
{
    using (ShimsContext.Create())
    {
        ShimBarcodeReader.Constructor = @this =>  new ShimBarcodeReader(@this) {
            ReadCode = () => "IC1234567890BLABLABLA",
        };
        MyLogic sut = new MyLogic();
        var industrialCode = sut.RetrieveIndustrialCode();
        Assert.Equal("1234567890", industrialCode);
    }
}

Whenever you fake an assembly, each Shim that gets created has one or more static property called ConstructorXXX, where the XXX part is used to distinguish from the overloaded version using paramers type. In this example I have a default constructor so my Shim has a static property called Constructor. This specific property permits you to intercept the future creation of that type and even substitute it with a shim. This specific property needs a lambda where the first parameter is the Instance of the object being created followed by all other parameters of the constructor. In my sample test I pass a lambda that based on the instance created, returns a new ShimBarcodeReader configured to return the code “IC1234567890BLABLABLA” from ReadCode() method.

This technique is really powerful because permits you to Shim every future instance that will be created for a specific object and makes possible to inject Shims almost everywhere. When the test run, the MyLogic constructor creates an instance of BarcodeReader, but thanks to the Shim library I’m able to pass a shim where I’ve already set the return value of ReadCode() method.

Thanks to this capability I can write tests until I eventually found a bug, to show how the Shim Constructor changes when constructor has parameters, I’ve changed the BarcodeReader class to make the constructor accepts a Single String parameter and I want to write a test that verify that when the BarcodeReader returns an Empty String the Industrial code returned is also Empty.

[Fact]
public void verify_retrieval_of_industrialCode_too_short()
{
    using (ShimsContext.Create())
    {
        ShimBarcodeReader.ConstructorString = (@this, value) => new ShimBarcodeReader(@this)
        {
            ReadCode = () => "",
        };
        MyLogic sut = new MyLogic("COM2");
        var industrialCode = sut.RetrieveIndustrialCode();
        Assert.Equal("", industrialCode);
    }
}

To shim the creation of a ShimBarcodeReader I now need to use ConstructorString property, since the constructor has now a parameter of type String. Thanks to Visual Studio 2012 and Shim Library you can now easily test untestable legacy code with minimum effort.

Gian Maria.

Shim and InstanceBehavior fallthrough to isolate part of the SUT

I’ve dealt in a previous post with the new Shim library in Vs11 that permits you to test “difficult to test code” and I showed a really simple example on how to use Shim to isolate the call to DateTime.Now to simulate passing time in a Unit Test. Now I want to change a little bit the perspective of the test, in the test showed in previous post I simply exercise the sut calling Execute() a couple of time, simulating the time that pass between the two calls. Here is the test

[Fact]
public void Verify_do_not_execute_task_if_interval_is_not_elapsed()
{
    using (ShimsContext.Create())
    {
        Int32 callCount = 0;
        PerformHeavyTask sut = new PerformHeavyTask(10, () => callCount++);
        DateTime startDate = new DateTime(2012, 1, 1, 12, 00, 00);
        ShimDateTime.NowGet = () =>  startDate;
        sut.Execute();
        ShimDateTime.NowGet = () => startDate.AddMinutes(9);
        sut.Execute();
        Assert.Equal(1, callCount);
    }
}

I can also change the point of view and write a test that uses a shim to isolate the SUT, this is a less common scenario but it can be also really interesting, because it shows you how you can write simple White box Unit Tests isolating part of the SUT. The term White Box is used because this kind of Unit Test are created with a full knowledge of the internal structure of the SUT, in my situation I have a private method called CanExecute() that return true/false based on the interval of time passed from the last execution and since it is private it makes difficult for me to test the SUT.

private Boolean CanExecute() {

    return DateTime.Now.Subtract(lastExecutionTime)
        .TotalMinutes >= intervalInMinutes;
}

But I can create a Shime on the SUT and isolate calls to the CanExecute(), making it return the value I need for the test, here is an example

[Fact]
public void Verify_can_execute_is_honored()
{
    using (ShimsContext.Create())
    {
        Int32 callCount = 0;
        PerformHeavyTask sut = new PerformHeavyTask(10, () => callCount++);
        ShimPerformHeavyTask shimSut = new ShimPerformHeavyTask(sut);
        shimSut.InstanceBehavior = ShimBehaviors.Fallthrough;
        shimSut.CanExecute = () => false;
        sut.Execute();
        Assert.Equal(0, callCount);
    }
}

To write this test I’ve added another fake assembly on the assembly that contains the PerformHeavyTask class to create shim for the SUT. This test basically create a ShimPerformHeavyTask (a shim of my SUT) passing an existing instance to the SUT to the constructor of the shim, then I set the InstanceBehavior to ShimBehaviors.Fallthrough to indicate to the Shim Library to call original SUT method if the method was not isolated. At this point I can simply isolate the call to the CanExecute() private and non-virtual method, specifying to the shim to return the value false, then I call the Execute() method and verify that the heavy task is not executed.

This test shows how to create a shim of the SUT to isolate calls to its private methods, thanks to the Fallthrough behavior; if you forget to change the InstanceBehavior the test will fail with an exception of type ShimNotImplementedException, because the default behavior for a Shim is to throw an exception for any method that is not intercepted. Thanks to shim library you can simply isolate every part of the SUT, making easier to write Unit Test for classes written with no TDD and no Unit Testing in mind.

Gian Maria.