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
I have a singleton that I need to have initialize normally. Everything was working fine until a test that mocked a call on the singleton got created that ran before the singleton gets to initialize normally. Here is the mocked call.

using(RecordExpectations recorder = RecorderManager.StartRecording()){
            recorder.ExpectAndReturn(ApplicationSettings.Instance.AccountImpersonationTicketTimeout, 30);
            
}


Now on subsequent tests if I access
ApplicationSettings.Instance

in an unmocked call, Instance is null.

Is there any way to prevent this?
asked by juice_johnson (9.8k points)

10 Answers

0 votes
Hi
Can you please post the Instance property code?
If you have static constructor for the ApplicationSettings class
please post it too.
answered by ohad (35.4k points)
0 votes
Here is the relevant code for ApplicationSettings class. there is no static constructor.

public class ApplicationSettings : EnvironmentSettings {

      
      private static readonly ApplicationSettings _instance = Singleton<ApplicationSettings>.Instance;


      public static ApplicationSettings Instance{
         get {
            return _instance;
         }
      }
                ...
}


public class EnvironmentSettings {

      public EnvironmentSettings() {
         this.LoadConfigSettings();
      }
                ...
}


and here is the code for the singleton

public static class Singleton<T> where T : class{

      public static readonly T Instance = typeof(T).InvokeMember(typeof(T).Name,
                     BindingFlags.CreateInstance |
                     BindingFlags.Instance |
                     BindingFlags.NonPublic, null, null, null, CultureInfo.InvariantCulture) as T;
      
   }  


please let me know if I can provide anything else to help with diagnosing this issue.
answered by juice_johnson (9.8k points)
0 votes
Hi
There's a problem with the code you posted:
The Singleton class is declared static so it can't have non-static members.
But in InvokeMember method you specify BindingFlags.Instance.
This will result a MissingMethodException when ever the
class is not mocked.

I'm not clear about two things:
Is this a problem only in the posted code?
Do you want to mock all calls to ApplicationSettings.Instance?
answered by ohad (35.4k points)
0 votes
There isnt a problem with the code I posted. Its a generic template for the singleton pattern. And it creates an instance of the type param. Do I need to explain more? I assume if you read the code more thoroughly you will see what is going on.

As for your questions.
I only want to mock the chained statement. I don't want to always mock Application.Instance. Thats my problem. Please reread the initial post. I need the static field _instance of ApplicationSettings to initialize properly. According to the documentation, this should occur automatically.

This is a snippet from the All About Constructors in the documentation.

Static Constructors will always be called. To mock a static constructor call recorder.MockStaticConstructors() this will mock all the static constuctors that where called while recording


So since I havent mocked any static constructors, I would assume that the static field should initialize properly. That is the problem.

Do you understand the problem now?
answered by juice_johnson (9.8k points)
0 votes
Hi
It seems to me that you need to clear the mock
using MockManager.ClearAll method.
What happens is the mock of the Singleton object is alive and
messing the other tests.
Try this:
using (RecordExpectations recorder = RecorderManager.StartRecording())
{
  recorder.ExpectAndReturn(ApplicationSettings.Instance.AccountImpersonationTicketTimeout, 30);   
}

Assert.AreEqual(30, ApplicationSettings.Instance.AccountImpersonationTicketTimeout);
MockManager.ClearAll();
answered by ohad (35.4k points)
0 votes
I have a VerifyMock attribute on the test. Seems like calling MockManager.ClearAll would invalidate that, right? So are you telling me that the documentation is wrong and static constructors arent always called? or are you telling me there is a bug in typemock?
answered by juice_johnson (9.8k points)
0 votes
Hi,

There problem here is that the code is using a public field, TypeMock at this time does not mock fields, so to mock the singleton correctly you would use:
public static class Singleton<T> where T : 
{
   private static readonly T instance = 
     typeof(T).InvokeMember(typeof(T).Name,
     BindingFlags.CreateInstance | 
     BindingFlags.Instance | 
     BindingFlags.NonPublic, null, null, null, 
     CultureInfo.InvariantCulture) as T;
        
   public static T Instance
   {
      get { return instance; }
    }
}


In any case as a workaround until we implement mocking fields, if you don't want to use a property in the Singleton class, is to call ApplicationSettings.Instance before the recording
e.g.
ApplicationSettings dummy = ApplicationSettings.Instance;
using (RecordExpectations recorder = RecorderManager.StartRecording())
{  recorder.ExpectAndReturn(ApplicationSettings.Instance.AccountImpersonationTicketTimeout, 30);
}
answered by scott (32k points)
0 votes
That doesnt make since then, if TypeMock doesnt mock fields then why is it mocking the field? Plus, im not trying to mock a field, im trying to mock a chained statement that includes a property.

this is the statement im trying to mock

ApplicationSettings.Instance.AccountImpersonationTicketTimeout


where Instance is a property. The code for the property is shown on a prior post on this thread.

The instance field on the singleton template is a field and maybe that is where the confusion is coming in. ApplicationSettings and Singleton<T> are not the same type.
answered by juice_johnson (9.8k points)
0 votes
Hi,
Actually the situation is more complex then we thought. Its related to TypeMock special handling of static constructors along when using Natural Mocks.

Its seems that there is an internal difference in the way the CLR treat the static constructor if its automatically generated or user defined.

In short it looks that there is an internal problem with the way TypeMock is handling the genereated Static constructor resulting in it not being called in the given scenario.

a workaround for this is either wrapping the field with a property, manually initiating a call to the instance before the recording block (as Scott showed you)
Another possibility to solve this is to move the initialization of the Instance field into an explicit static constructor

In any case we will let you know when a fix for this will be available.
Hope this clear things a little.
answered by ohad (35.4k points)
0 votes
thank you for looking deeper into this. I have implemented one of the workarounds for the time being.
answered by juice_johnson (9.8k points)
...