Search code examples
c#visual-studiounit-testingmicrosoft-fakesshim

c# unit testing with fakes: when and how to setup/dispose ShimsContext's idisposable... and if I don't...?


In visual studio 2012+, I am using Shims to allow the testing of legacy code without accessing the database. I am using the MSTest framework.

I am trying to avoid code duplication of setting up the shims multiple times; I have instead set up a helper method (e.g. below, BuildShim()) to do so. The idea is that by having the ShimObject built in the helper method, I can have it available for each of the Test methods in my test class.

In the constructor for the test class, I initialize a _idisposable = ShimsContext.Create() (which actually returns an IDisposable). In the methods, I have try {} and finally { _idisoposable.Close() };

Microsoft explicitly advises (see http://msdn.microsoft.com/en-us/library/hh549176.aspx ) using a ShimContext like this, however:

using (ShimsContext.Create()){

...

} 

Questions:

  1. Is it bad that I'm not doing it the Microsoft way? If I do it the Microsoft way, how can I avoid duplicating Shim setup code? Or it okay to put the ShimsContext initialization in the constructor and disposal in the finally {} blocks as long as I know what I'm getting into? (e.g. it might be bad if I were using ShimObject.AllInstances type methods, since I could accidentally affect a property in one place and inadvertently affect it elsewhere.)

  2. Is there anything wrong creating the ShimsContext in the test constructor and disposing the _shimcontextDisposal in the finally block like this instead?

  3. What happens if I don't dispose of ShimsContext? Will my computer blow up, figuratively? (e.g. will the shims never be unloaded and I would start to get weird behavior if I actually run the app?)

Example code below.

[TestClass()]
public class Tests {

//Variable to store ShimsContext idisposable.  Note that we're not holding the ShimsContext,
//but rather the IDisposable object returned by the ShimsContext.Create() method
private IDisposable _shimscontextDisposable;

//Test class constructor
public Tests(){
_shimscontextDisposable = ShimsContext.Create();
}

//Test method
[TestMethod()]
public TestMethod1(){
try {

//Call the helper method below to get the shim
ShimObject shim = this.GetShimObject();
DataObject data = shim.Instance;

//... do something in test method 1

}
finally {
_shimscontextDisposable.Dispose();
}

}

//Test method 2
[TestMethod()]
public TestMethod2(){
try {

//Call the helper method below to get the shim
ShimObject shim = this.GetShimObject();
DataObject data = shim.Instance;

//... do something in test method 2    
}
finally {
_shimscontextDisposable.Dispose();
}
}

//Reusable method to Build shims across methods, avoid duplicating shim setup
public ShimObject BuildShim(){

ShimObject shim = new ShimObject();
shim.TitleGet = () => { return "title"; };
shim.UrlGet = () => { return new Uri("http://www.google.com"); };

return shim;

}

Solution

  • For MSTest Unit Tests it is best practice not to use a constructor. Instead use the ClassInitialize or TestInitialize attribute methods, followed by the TestCleanup or ClassCleanup attribute methods.

    For your case, you would set your IDisposable object in the Initialize and dispose of it in the Cleanup.

    http://msdn.microsoft.com/en-us/library/microsoft.visualstudio.testtools.unittesting.classinitializeattribute.aspx

    namespace TestNamespace
    {
        [TestClass]
        public class DivideClassTest
        {
            [ClassInitialize]
            public static void ClassInit(TestContext context)
            {
            }
    
            [TestInitialize]
            public void Initialize()
            {
            }
    
            [TestCleanup]
            public void Cleanup()
            {
            }
    
            [ClassCleanup]
            public static void ClassCleanup()
            {
            }
        }
    }