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
Welcome to Typemock Community! Here you can ask and receive answers from other community members. If you liked or disliked an answer or thread: react with an up- or downvote.
0 votes
Hi there,
I've been seeing a problem with some tests that I have being trying to write, where I mock a singleton that is used by a worker thread.

I have boiled the problem down to it's constituent parts, and here is code that I was expecting to pass, but doesn't. Can you help me put this right?

I can see that it is failing because the ACTUAL singleton method is being called, rather than the expectation on the mock singleton, but I have followed the guidance on mocking singletons, and yet this does not work.

using System;
using System.Threading;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using TypeMock;

namespace Ammado.Web.Interactive.ServiceImpl.Tests {
   [TestClass]
   public class AsyncTest {
      [TestInitialize()]
      public void MyTestInitialize()
      {
         MockManager.Init();
      }


      [TestMethod]
      public void TestMethod1()
      {
         ClassUnderTest classUnderTest = new ClassUnderTest();

         Mock mockedDependant = MockManager.MockAll(typeof (DependantClass), Constructor.StaticNotMocked);
         mockedDependant.Strict = true;

         mockedDependant.ExpectAndReturn("DoSomething", "string from MOCKED DependantClass");

         classUnderTest.MethodUnderTest();

         MockManager.VerifyWithTimeout(5 * 1000);
         
         Assert.AreSame("string from MOCKED DependantClass", classUnderTest.Message);
      }
   }


   public class ClassUnderTest {
      public string Message;
      
      public void MethodUnderTest()
      {
         Console.WriteLine("ClassUnderTest: MethodUnderTest");

         WaitCallback callback = new WaitCallback(Process);

         ThreadPool.QueueUserWorkItem(callback);
      }


      public void Process(object state)
      {
         Console.WriteLine("ClassUnderTest: Process");

         Message = DependantClass.Instance.DoSomething();
      }
   }


   public class DependantClass {
      #region SINGLETON

      private static volatile DependantClass _instance;
      private static object _singletonSyncRoot = new Object();


      private DependantClass()
      {
      }


      public static DependantClass Instance
      {
         get
         {
            if (_instance == null) {
               lock (_singletonSyncRoot) {
                  if (_instance == null)
                     _instance = new DependantClass();
               }
            }

            return _instance;
         }
      }

      #endregion

      public string DoSomething()
      {
         return "String from REAL DependantClass";
      }
   }
}

________
VAPORIZER VOLCANO
asked by pmcevoy (4.7k points)

5 Answers

0 votes
Hi
Your problem is not connected to singelton class but rather to a threading problem

The ExpectAndReturn does not ensures in this case that the retuned value is assigned to the caller before a context switch.

The code below will do the job:
[TestMethod] 
public void TestMethod1() 
{
    ClassUnderTest classUnderTest = new ClassUnderTest(); 

    Mock mockedDependant = MockManager.MockAll(typeof (DependantClass), Constructor.StaticNotMocked); 
    mockedDependant.Strict = true;

    mockedDependant.ExpectAndReturn("DoSomething", "string from MOCKED DependantClass"); 
    classUnderTest.MethodUnderTest();
              
    mockedDependant.VerifyWithTimeout(5000);
    Thread.Sleep(5000);                
    Assert.AreSame("string from MOCKED DependantClass", classUnderTest.Message);          
} 
answered by ohad (35.4k points)
0 votes
Doh!

I was about to post a ranting reply about how could adding a Thread.Sleep to the test fix this, and it took me a while to see that you have changed from

MockManager.VerifyWithTimeout

to

mockedDependant.VerifyWithTimeout

in fact, the Thread.Sleep is not necessary at all, as VerifyWithTimeout blocks for the timeout anyway.

What I am confused about now, is WHEN I should be doing this? The documentaiton says to use MockManager.VerifyWithTimeout?

If I change my code to NOT be a singleton, and just be a class instantiated by the worker thread, then MockManager.VerifyWithTimeout works as advertised (see below).

Perhaps the docs need to be updated?

Thank you for the help though!

Sincerely
Pete


   public class AsyncTest {
      [TestInitialize()]
      public void MyTestInitialize()
      {
         MockManager.Init();
      }


      [TestMethod]
      public void TestMethod1()
      {
         ClassUnderTest classUnderTest = new ClassUnderTest();

         Mock mockedDependant = MockManager.Mock(typeof (DependantClass));
         mockedDependant.Strict = true;
         mockedDependant.ExpectAndReturn("DoSomething", "string from MOCKED DependantClass");

         classUnderTest.MethodUnderTest();

         MockManager.VerifyWithTimeout(5 * 1000);
         
         Assert.AreSame("string from MOCKED DependantClass", classUnderTest.Message);
      }
   }


   public class ClassUnderTest {
      public string Message;


      public void MethodUnderTest()
      {
         WaitCallback callback = new WaitCallback(Process);

         ThreadPool.QueueUserWorkItem(callback);
      }


      public void Process(object state)
      {
         DependantClass dependantClass = new DependantClass();
         Message = dependantClass.DoSomething();
      }
   }


   public class DependantClass {
      public string DoSomething()
      {
         return "String from REAL DependantClass";
      }
   }

________
BMW M2B15 HISTORY
answered by pmcevoy (4.7k points)
0 votes
You are right this is a bug.
We fixed the bug and I'm sending the patch offline.
So check your mailbox :D
answered by ohad (35.4k points)
0 votes
Here are the details of the bug.
MockManager.VerifyWithTimeout did not verify MockAll expectations.
answered by scott (32k points)
0 votes
Thanks Guys!
Your support is second to none! I'll verify once I get the patch (I've sent you a non-filtering email address that should recieve the patch file)

Sincerely
Pete
________
Mexicocity Hotel
answered by pmcevoy (4.7k points)
...