chevron-thin-right chevron-thin-left brand cancel-circle search youtube-icon google-plus-icon linkedin-icon facebook-icon twitter-icon toolbox download check linkedin phone twitter-old google-plus facebook profile-male chat calendar profile-male
0 votes
Hi

I have a straightforward singleton class where you call a static GetInstance(), which then returns an instance of the class. I thought it would be a simple matter of mocking that up, but I'm running into a very frustrating problem ! I can't seem to make GetInstance() return my mocked object correctly with my expected calls set.

I've tried:

* using MST projects (using the Accessor classes) to assign a mocked object directly to the instance variable (faking the object using Memers.MustSpecifyReturnValues, and Isolate.WhenCalled using WithExactArguments to set expectations), but for some reason the mocked object _always_ returns null (and no exceptions).
* Mocking Singleton.GetInstance() to return the mocked object. This returns a mocked object which needs WhenCalled set, but now the Isolate.WhenCalled calls I make seem to do nothing on the fake object - so all calls throw an unexpected call exception.
* I've also tried mocking the actual method call (eg Singleton.GetInstance().Test()), which will work for the call to that method, but all other calls to other methods on the singleton return null rather then throw an exception as I want it to (because this seems to automatically mock up all the objects without Members.MustSpecifyReturnValues).

All I want is to mock a singleton, and any calls I don't explicitly tell it to expect to throw an exception on. I thought it would be simple, but apparently not ! :(

Has anyone any idea what I'm doing wrong?

Thanks
James
asked by jamesdill (640 points)

4 Answers

0 votes
Not sure if this will help, but here's a bit of a simple example

Here's the class I used, and I use a property called "Current" to retrieve it.
public class MySingleton
{
   private static MySingleton mySingleton;

   // Private so you won't be able to initiate it
   private MySingleton()
   {
      Console.WriteLine("This won't be executed if faked/isolated.");
   }

   public static MySingleton Current
   {
      get
      {
         if (mySingleton == null)
            mySingleton = new MySingleton();

         return mySingleton;
      }
   }

   public string IsolateProperty
   {
      get { return "original"; }
   }
}


Note that the above code is NOT thread safe! You need to use the "lock" statement.

Now I use the following test to see if it really is a singleton.

[TestMethod]
public void MultipleRetrievalsResultInSameInstance()
{
   // Act
   MySingleton first = MySingleton.Current;
   MySingleton second = MySingleton.Current;

   // Assert
   Assert.AreSame(first, second);
}


and the code below will make sure the instantiated instance is a fake instance.

[TestMethod]
public void FakeTheCreationOfInstance()
{
   const string STR_Faked = "faked";

   // Arrange
   var fake = Isolate.Fake.Instance<MySingleton>();
  Isolate.WhenCalled(() => fake.IsolateProperty).WillReturn(STR_Faked);
   Isolate.Swap.NextInstance<MySingleton>().With(fake);

   // Act
   MySingleton first = MySingleton.Current;

   // Assert
   Assert.AreEqual(STR_Faked, first.IsolateProperty);
}
answered by dvdstelt (5.3k points)
0 votes
Hi James,

I think the simple solution will be to create a fake instance of the singleton class and use SwapNextInstace before the actual class constructor is called:
[TestMethod]
public void SetBehaviorOnSingleton()
{
    var fake = Isolate.Fake.Instance<SingletonClass>();

    // Set additional behavior on singleton class
    Isolate.WhenCalled(() => fake.SomeFunction()).WillReturn(10);

    Isolate.Swap.NextInstance<SingletonClass>().With(fake);

    // This is where the class constructor is being called
    var result = SingletonClass.GetInstace().SomeFunction();
    Assert.AreEqual(10, result );
}


This solution should work with most scenarios unless the singleton class is created before the test.
If you need to set behavior after the class was created just use WhenCalled:
[TestMethod]
public void SettBehaviorOnSingleton()
{
    var fake = Isolate.Fake.Instance<SingletonClass>();

    Isolate.WhenCalled(() => fake.SomeFunction()).WillReturn(10);

    Isolate.WhenCalled(() => SingletonClass.GetInstace()).WillReturn(fake);


    var result = SingletonClass.GetInstace().SomeFunction();
    Assert.AreEqual(10, result );
}


Either way should work for you, in case you still have problems faking a singleton - please post a code snippet of your test so we can investigate it together
answered by dhelper (11.9k points)
0 votes
Thanks for your answers guys (again :) ).

I've continued over here to prevent duplications....

http://stackoverflow.com/questions/7250 ... 641#726641
answered by jamesdill (640 points)
0 votes
Or with Unity

[TestMethod]
public void TestName()
{
   IUnityContainer container = new UnityContainer();
   container.RegisterType<MySingleton, MySingleton>(new ContainerControlledLifetimeManager());

   MySingleton first = container.Resolve<MySingleton>();
   MySingleton second = container.Resolve<MySingleton>();

   Assert.AreSame(first, second);
}
answered by dvdstelt (5.3k points)
...