Microsoft Fakes and real object constructor
I'm using .NET 4.8 and Microsoft Fakes to create Shim object for unit testing. This class (KRSampleManager) is using Lazy initialization to create an instance and implements IDisposable interface.
namespace SampleManager
{
public class KRSampleManager : IDisposable
{
private Dictionary<string, string> _events = null;
private KRSampleManager()
{
_events = new Dictionary<string, string>();
}
private static readonly Lazy<KRSampleManager> _lazy =
new Lazy<KRSampleManager>
(() => new KRSampleManager());
private bool _isDisposed;
protected virtual void Dispose(bool disposing)
{
if (_isDisposed && disposing)
{
_isDisposed = true;
}
}
public static KRSampleManager Instance
{
get { return _lazy.Value; }
}
public void Dispose()
{
_events.Clear();
Dispose(true);
GC.SuppressFinalize(this);
}
public int Count()
{
return _events.Count();
}
public bool IsNull()
{ return _events == null; }
}
}
there is another SampleHandler class which is using the KRSampleManager class
namespace SampleHandler
{
public class SampleHandler
{
private bool _isnull;
public SampleHandler()
{
_isnull = SampleManager.KRSampleManager.Instance.IsNull();
}
}
}
there are two unit test classes in same unit test project. UnitTest1 class creates a ShimKRSampleManager and tries to create SampleHandler object
public class UnitTest1
{
[TestMethod]
public void TestMethod3()
{
using (ShimsContext.Create())
{
ShimKRSampleManager.Constructor = (c) => { };
var handler = new SampleHandler.SampleHandler();//SampleHandler.SampleHandler.Instance;
Assert.IsNotNull(handler);
}
}
}
UnitTest2 class just creates a real KRSampleManager instance and dispose it.
[TestClass]
public class UnitTest2
{
[TestMethod]
public void TestMethod2()
{
var s = KRSampleManager.Instance;
s.Dispose();
}
}
When running unit tests, if UnitTest1 executes first, then UnitTest2 fails with System.NullReferenceException: Object reference not set to an instance of an object for KRSampleManager.Dispose() method for _events.Clear(). Adding logs indicate that the constructor for KRSampleManager never gets called if UnitTest1 test is run first. If I change the name of UnitTest1 class to UnitTest3, so that it executes after UnitTest2, both unit tests pass. This seems to be problem with Microsoft Fakes. If I keep UnitTest1 and UnitTes2 classes in separate project both tests pass.