Patrick Desjardins Blog
Patrick Desjardins picture from a conference

How to unit test a method that is not from an interface, neither virtual with Visual Studio 2012

Posted on: 2013-09-03

Microsoft has the ability to fake method but as the disadvantage that it requires to be from an interface or to be virtual. This is the case of most testing framework. Nevertheless, Microsoft has the principle of Shim which allow to replace the method behavior by yours for the time of a test. You can get additional information on MSDN. This blog article explains briefly how to use shim.

For the purpose of this article, let say that we have a library with a single class which contain a single method :

namespace ShimpProjectClassesToShim { 
  public class MyClass { 
    public string MyMethod(string variable) { 
      return "From MyClass = " + variable; 
    } 
  } 
  
  public class MyClass2 { 
    public string ToTest() { 
      var m = new MyClass();
      return m.MyMethod("InsideMyClass2"); 
    } 
  } 
}

This method is not virtual, but could have been because shim can be bound to static method. As you can see, the purpose of the test would be to change the inside of the method for the time of a test method.

To continue with our example, we need a second project, the one of the test. This one will have a reference to the library previously created. Once done, right click the reference and click "Add Fake Assembly".

Do no worry, you have already added the reference from the unit project to the library project. Maybe a better naming of the action should have been "Transform to Fake Assembly. When done, you will see a Fakes folder created with the fake reference.

If you are curious about what contain this file, here is the one of the example :

 <Fakes xmlns="http://schemas.microsoft.com/fakes/2011/"> 
  <Assembly Name="ShimpProjectClassesToShim"/> 
 </Fakes> 

So the test will consist of shimming MyClass that is used by MyClass2. This is a common scenario that you want to test a method that use an other class that you do not want to test. In our case, we want to test MyClass2 and not MyClass, we shim MyClass to have a known return value.

The test my be inside the scope of a ShimContext to be able to set the shim inside the test.

[TestClass] public class UnitTest1 { 
  [TestMethod] public void TestMethod1() { 
    //Shim 
    using (ShimsContext.Create()) { 
      //Arrange 
      ShimMyClass.AllInstances.MyMethodString = (theClass, s) => "FAKE " + s; 
      var classToUnitTest = new MyClass2();

      //Act 
      string result = classToUnitTest.ToTest();

      //Assert 
      Assert.AreEqual("FAKE InsideMyClass2", result); 
    } 
  } 
} 

The arrange section set for all instances of the method the desired return value. As you can see we use "ShimMyClass" class to set all instances. In your case, if you class is called "XYZ", you will have to use "ShimXYZ". This is by design that a class has been created for you with the prefix Shim. From there, you will be able to set return value for all methods. The rest of the unit test is as usual.