Mscorlib mocking minus the attribute
Mocking .net framework members (a.k.a. mscorlib) is always a daunting task. It’s the breed of static and final methods and full of surprises. Technically intercepting mscorlib members is completely different from other class libraries. This is the reason it is dealt differently. Generally, I prefer writing a wrapper around an mscorlib member (Ex. File.Delete(“abc.txt”)) and expose it via interface but that is not always an easy task if you already have years old codebase.
While mocking mscorlib members first thing that comes to people’s mind is DateTime.Now. If you Google through, you will find tons of example dealing with just that. May be it’s the most important class that we can’t ignore and I will create an example using JustMock Q2 with the same.
In Q2 2012, we just get rid of the MockClassAtrribute for mocking mscorlib members. JustMock is already attribute free for mocking class libraries. We radically think that vendor specific attributes only makes your code smelly and therefore decided the same for mscorlib.
Now, I want to fake DateTime.Now for the following class:
public class NestedDateTime
public DateTime GetDateTime()
It is the simplest one that can be. The first thing here is that I tell JustMock “hey we have a DateTime.Now in NestedDateTime class that we want to mock”.
To do so, during the test initialization I write this:
Mock.Replace(() => DateTime.Now).In<NestedDateTime>(x => x.GetDateTime());
I can also define it for all the members in the class, but that’s just a waste of extra watts.
Mock.Replace(() => DateTime.Now).In<NestedDateTime>();
Now question, why should I bother doing it? The answer is that I am not using attribute and with this approach I can mock any framework members not just File, FileInfo or DateTime. Here to note that we already mock beyond the three but when nested around a complex class, JustMock was not intercepting it correctly. Therefore, we decided to get rid of the attribute altogether fixing the issue.
Finally, I write my test as usual.
public void ShouldAssertMockingDateTimeFromNestedClass()
var expected = new DateTime(2000, 1, 1);
Mock.Arrange(() => DateTime.Now).Returns(expected);
Assert.Equal(new NestedDateTime().GetDateTime(), expected);
That’s it, we are good. Now let me do the same for a random one, let’s say I want mock a member from DriveInfo:
Mock.Replace<DriveInfo>(() => DriveInfo.GetDrives()).In<MsCorlibFixture>(x => x.ShouldReturnExpectedDriveWhenMocked());
Moving forward, I write my test:
public void ShouldReturnExpectedDriveWhenMocked()
Mock.Arrange(() => DriveInfo.GetDrives()).MustBeCalled();
Here is one convention; you have to replace the mscorlib member before executing the target method that contains it. Here the call to DriveInfo is within the MsCorlibFixture therefore it should be defined during test initialization or before executing the test method.
Hope this gives you the idea.