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 did a quick search if this had been reported below, but I admit it was a quick search. It looks like there is an interesting bug related to static classes and static members and they being mocked as null or Empty without any request to mock them. I will try to describe it below with code.
FYI I am using version 4.1

Say I have this code in its own assembly/project (It is important that it is in a separate assembly than the test assembly).

using System;

namespace UnderTest
{
public class StaticCls
{
public static Guid Guid1 = new Guid("{11223344-5566-7788-9900-aabbccddeeff}");
public static string String1 = "static string1's value";
public static int[] IntArr1 = new int[] { 1, 2, 3, 4, 5 };
}

public class CUT
{
public static string StaticString = "static string";
public string Method1()
{
return string.Format("StaticCls Guid1:{0}", StaticCls.Guid1);
}

public bool Method2()
{
return StaticCls.Guid1.Equals(new Guid("{11223344-5566-7788-9900-aabbccddeeff}"));
}
}
}


Then I have this line of codes in the tester assembly:


[TestFixture]
public class Class1
{

[SetUp]
public void SetUp()
{
MockManager.Init();
}

[TearDown]
public void TearDown()
{
MockManager.Verify();
MockManager.ClearAll();
//Assert.AreEqual(StaticCls.String1, "static string1's value");
//Assert.AreEqual(StaticCls.Guid1, new Guid("{11223344-5566-7788-9900-aabbccddeeff}"));
Assert.AreEqual(CUT.StaticString, "static string");


}

[Test]
public void Test1()
{
CUT cut = (CUT)MockManager.MockObject(typeof(CUT)).MockedInstance;
using (RecordExpectations recorder = RecorderManager.StartRecording())
{
recorder.ExpectAndReturn(cut.Method1(), "some string").RepeatAlways();
}

Assert.AreEqual(cut.Method1(), "some string");
}

The problem is, when Test1() method executes, because nothing yet referenced the assembly that defines StaticCls, and CUT, their static constructor hasn't been executed yet by the compiler, and their static members aren't initialized yet.

Inside the recording block Method1() of CUT class is being told to be mocked. Strange thing is, this recording call causes somehow TypeMock to decide to mock all of StaticCls's static members and CUT.StaticString member, and they are all mocked as null or in case of Guid1 as Guid.Empty.

And this mocking behaviour of the static members as null/Empty doesn't stop even after calling MockManager.ClearAll().
As you can see I have added Assert statements in the TearDown() that checkes the values of the static members, and they all fail.

If on the other hand those Assert statements were moved to Setup() method, the bug is avoided, because those allows the compiler to initialize the static members correctly, before TypeMock decides to mock them as null/Empty. And my guess is TypeMock seeing they are already initialized leaves them alone.

I want to point out again that it is important that the test class and the class under test and the other small static class to be on different assemblies, so that delayed execution of the static members are more obvious. And on debugger if you try to watch the values of these static members, sometimes by just the fact that they are listed as watch variables under debugger causes them to be initialized by run time correctly. So best way to replicate this would be to run the test without debugging.

Could you please take a look at this? My apologies if this had been already discussed, or I am missing something else also.

TIA
asked by phazer (4k points)

5 Answers

0 votes
Hi,

It does look like there's a bug here :evil: , where the static constructor is not initialized before the call to the TearDown function.

We'll investigate this and get back to you. As a workaround, you can use the following code line, which makes sure the static constructor is called:

CUT cut = (CUT)MockManager.MockObject(typeof(CUT), Constructor.StaticNotMocked).MockedInstance;


PS.
Guids are structs (value types) and as such, have no instances. And therefore are treated differently than class instances. See here:
https://www.typemock.com/community/viewt ... truct#2756
answered by gilz (14.5k points)
0 votes
Thanks for the reply but I think you are missing some of what I tried to describe. For instance, there is no code in the recording block to tells to mock the "StaticCls" class, unlike the CUT class. And yet, its static members gets mocked as null or empty, because they hadn't been initialized yet by the run time. This behaviour is dangerous, it is mocking members of classes that never have been told to mock any part of them. And this mocking doesn't get cleared up even after MockManager.Clear().
answered by phazer (4k points)
0 votes
Hi,

Thanks for explaining further. The bug I was referring to also includes the behavior you were witnessing. Namely, implicit types initializers (including static constructors) are not called. We will investigate this and try to resolve it as quickly as possible.

Is the workaround using reflective mocks useful for you?
answered by gilz (14.5k points)
0 votes
Yes, using reflective mocks, the StaticCls is not getting mocked. But for CUT's static members, I have to explicity tell Constructor.StaticNotMocked as you wrote.
answered by phazer (4k points)
0 votes
Hi,

The fix for this issue was included as part of the 4.22 release.
Static members from classes which were no explicitly mocked will not be mocked.
answered by lior (13.2k points)
...