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
There are a few issues that need to be taken in account when mocking Singleton classes.

:arrow: Mocking the constructor
:arrow: Mocking instances

Suppose we have a singleton class called singleton Singleton that has a foo() method that we want to mock.
The method will be called in the code as follows: Singleton.GetInstance().foo()
The Singleton might have a static initialization of itself:
static private Singleton instance = new Singleton();
public Singleton GetInstance() { return instance;}


We would normally mock using:
Mock singletonMock = 
    MockManager.Mock(typeof(Singleton),false);
singletonMock.ExpectCall("foo");

:!: We are sending false to tell TypeMock that we don't want our constructors to be mocked. This will allow our static initialization to run, so our Singleton code:
static private Singleton instance = new Singleton(); will run.
(See Mocking Constructors on how to mock the constructor but to keep the static initialization)

:!: But this won't work and a strange behaviour will appear. When we run a test alone it will work, but when we run a suite of tests they will start failing. We will find out that TypeMock, mocks the singleton only for the first test!

If we read the documentation, the MockManager.Mock method will mock the next creation of a Singleton object but if the Singleton exists already, for example in a previous test, the existing object will not be mocked. So the Above code will not work.

:idea: The correct way to mock singletons is to use the MockAll method:
Mock singletonMock = 
   MockManager.MockAll(typeof(Singleton),false);


This will mock existing objects as well, and because there is only one singelton object in the domain, we will be mocking the correct object.
asked by scott (32k points)

8 Answers

0 votes
Hi,
In version 2.2 the following code is the correct way to mock singletons
Mock singletonMock = 
   MockManager.MockAll(typeof(Singleton),
      Constructor.StaticNotMocked);

or
Mock singletonMock = 
   MockManager.MockAll(typeof(Singleton),
      Constructor.NotMocked);

depending on if we want to mock the constructor or not.
answered by richard (3.9k points)
0 votes
Im getting a weird problem with a singleton. I mock the the singleton in the fixture setup like this:

this._mockAuthorizationService = MockManager.MockAll(typeof(AuthorizationService), Constructor.Mocked);


I have to mock constructors because the class being mocked is really just a facade for another service that is expensive to create and this service gets created in the constructor. So I mock the constructors to prevent the creation. Stepping through the code appears that the constructors do not get mocked though.

Then in my tests I use the mock that I created in the fixture setup to mock the operations on the Authoriziation Service like this:
this._mockAuthorizationService.ExpectAndReturn("Authorize", false, 1).Args(policy.Principal, DomainPermission.Operation.Approve);
   


I get this error when MockManager.Verify is called:

RemoteNet.Northrop.IbisWork.UnitTests.Domain.Model.ProcedureContextFixture.CopyPermissionCanCopy :
TearDown : TypeMock.VerifyException :
TypeMock Verification: Method RemoteNet.Northrop.IbisWork.Utility.Security.AuthorizationService.Authorize() has 1 more expected calls


It is appearing that the actual code of the authorization service is called and the operation is not mocked at all.

The test works fine when it is run by itsself. When it runs as a suite of tests, the test fails.

Any help would be appreciated.
answered by jnapier (9.6k points)
0 votes
Hi,
Do you have a MockManager.Init() in the fixture?
What version are you using?
What happens if you use this._mockAuthorizationService.AlwaysReturn()?
answered by scott (32k points)
0 votes
Yes I have MockManager.Init in the fixture. I am using the latest patch that you sent me 3.0.0.2.

In the test I am checking the MockManager.IsTypeMockedAll and it is returning true. But the actual code of the method I have mocked is runnning.

AlwaysReturn has the same effect.

Now I am not getting the verify exception I mentioned in my last post though. Since you sent me the patch to resolve the other problem, I am now getting NullReferenceExceptions. The reason why I am getting these exceptioins is because I have mocked the constructors as I previosly mentioned. An expensive object is not getting created. When my code hits the operation that is supposed to be mocked, it is now trying to interact with the reference to the expensive object because TypeMock is not intercepting the call corrrectly, so that is why I am getting null reference exceptions.

Please let me know if I can provide any more information.
answered by jnapier (9.6k points)
0 votes
Ok,
This can happen because of different reasons, for example the instance variable being null and thus having a different behaviour.
This is why we created the TypeMock Tracer. 8)

Please do the following:
Start the Tracer (Start->All Programs->TypeMock.NET->Tracer).
Now run the test.

You will see exactly what instances and which methods are mocked in the top part of the view.
You will also see what methods where called (both mocked and unmocked) in real time sequence at the bottom part.

The views are hot linked. When selection an item in one view the related items in the other view are highlighted.

For more information see the User Guide

Please tell us your findings, or post/send a screenshot.
answered by scott (32k points)
0 votes
It appears we are in different time zones and I wont have a chance to try the tracing until tomorrow for me, but I just wanted to state a few things that might help with your diagnosis.

1) The instance variable being null should not be a factor because the operation that accesses the null instance variable should be mocked and the actual code should not run.

2) I turned off mocking for the constructors and allowed the instance variable to be instantiated. When run as a suite of tests, the instance variable is accessed and the actual code is run, again the operation was not mocked.
answered by jnapier (9.6k points)
0 votes
I dont have a version that allows tracing.
answered by jnapier (9.6k points)
0 votes
This topic was taken offline,

The problem is the following:
The code was setting up mocks in the [TestFixtureSetUp] but doing a MockManager.Verify in the [TearDown] method.

The MockManager.Verify will remove all expectation created in the FixtureSetUp.

In you want to do the setup only once you can do the following.

:arrow: Verify only the mocks that you have an Expectation setup. (e.g. mock.Verify)
:arrow: Do a MockManager.Verify in the [TestFixtureTearDown]
:arrow: Reset mocks that have been verified.
answered by scott (32k points)
...