Search code examples
c#unit-testingmicrosoft-fakesvs-unit-testing-framework

Fake static/singleton class/method using microsoft fakes


I have class which has private constructor and accessed through public static method ( singleton class). Not able to create singleton object of this class in fakes.

public class MyBusinessManager : BusinessManager
{
 private MyBusinessManager objMyBusinessManager;

 private MyBusinessManager (MyBusinessManager dvqsDataManager)
        {
           objMyBusinessManager= dvqsDataManager;
        }
 public static MyBusinessManager GetInstance() // out
        {
            MyBusinessManager dvqsDataMgr = new MyBusinessManager();

            return new MyBusinessManager (dvqsDataMgr);
        }

 public bool MyBusinessManagerMethod (int bm)
       {
              if(bm == 0)
                 return true;

              return false;
       }
 }

I want to Test Following method:

public class MyService
{
   public bool MyServiceMethod(int serviceParam)
   {
        MyBusinessManager dvqBusinessManager = MyBusinessManager.GetInstance(); // make fake call
        return dvqBusinessManager.MyBusinessManagerMethod(serviceParam); // make fake service call
   }
}

My Test class:

[TestClass]
public class MyService_UT
{
  [TestMethod]
  public void TestMethod1()
  {
      using (ShimsContext.Create())
      {
        ShimMyBusinessManager.GetInstance = () => { return new ShimMyBusinessManager(); };
        ShimMyBusinessManager.AllInstances.MyServiceMethodInt32 = (a) =>{
                               return true;
                                 }
       MyService obj = new MyService();
       Assert.IsTrue(obj.MyServiceMethod(1))// doesn't call fake method
       }
  } 
}

How to call fake method in this case? Unable to create instance of fake with this code.


Solution

  • I suggest to move creation of dvqBusinessManager outside of the method.

    This way

        MyBusinessManager dvqBusinessManager = MyBusinessManager.GetInstance();
        public bool MyServiceMethod(int serviceParam)
        {
            return dvqBusinessManager.MyBusinessManagerMethod(serviceParam); // make fake service call
        }
    

    Or

        public bool MyServiceMethod(int serviceParam)
        {
            MyBusinessManager dvqBusinessManager = MyBusinessManager.GetInstance();
            MyServiceTestableMethod(dvqBusinessManager, serviceParam);
        }
    
        public bool MyServiceTestableMethod(MyBusinessManager manager, int serviceParam)
        {
            return manager.MyBusinessManagerMethod(serviceParam);
        }
    

    So you can inject a fake object to the method and test it, without calling GetInstance method.

    Or you can implement and use a factory pattern and hide the static call there.

        public interface IServiceFactory 
        {
            MyBusinessManager GetInstance();
        }
    
        public class ServiceFactory : IServiceFactory
        {
            public MyBusinessManager GetInstance()
            {
                return MyBusinessManager.GetInstance();
            }
        }
    
        IServiceFactory factory = new ServiceFactory();
        public bool MyServiceMethod(int serviceParam)
        {
            MyBusinessManager dvqBusinessManager = factory.GetInstance();
            dvqBusinessManager.MyBusinessManagerMethod(serviceParam);
        }
    

    But if you still want to mock a static call without changing the code, you should use Shims like in this example http://www.richonsoftware.com/post/2012/04/05/using-stubs-and-shim-to-test-with-microsoft-fakes-in-visual-studio-11.aspx.