What is wrong with this code?
class Program
{
static void Main(string[] args)
{
DateTime dob = new DateTime(1967, 7, 9);
int days = CalcDays(dob);
Console.WriteLine($"Days: {days}");
}
private static int CalcDays(DateTime dob)
{
return (DateTime.Today – dob).Days;
}
}
Well, the code will work. But testing will become a problem because DateTime.Today
is a non-deterministic function. That means that it is possible that the function will return a different value when called at different times. In this case, it is clear that tomorrow the function will return something else than today or yesterday. So if you want to write a test for this function, you’ll need to change it every day. And actually, changing a test to make it pass isn’t exactly the idea of unit testing…
How Can We Solve This?
There is some work involved here. Let me draw what we’re going to implement:
I have shown this pattern in previous posts already. We are injecting the IClockService
into the Date
class. In the actual implementation, we then implement the CurrentDate
property as DateTime.Today
.
So now, we can create our test project and write some tests. In the tests, we will mock the IClockService
so that CurrentDate
becomes deterministic and we don’t have to modify our tests every day.
Our tests could look something like:
class FakeClockService : IClockService
{
public DateTime CurrentDate
{
get
{
return new DateTime(1980, 1, 1);
}
}
}
[TestClass()]
public class DateTests
{
[TestMethod()]
public void CalcDaysTest()
{
Date dt = new Date(new FakeClockService());
DateTime dob = new DateTime(1967, 7, 9);
int days = dt.CalcDays(dob);
Assert.AreEqual(4559, days);
}
}
As you can see, I have implemented a FakeClockService
that will always return a fixed date. So testing my code becomes easy.
But if I want to test my code with different fake values for CurrentDate
, I will need to implement the interface for each of these different values. In this simple case, the interface contains 1 simple method, so besides messing up my code, that is not a big problem. But when your interface becomes larger, this becomes a lot of work.
Enter MOQ
According to their website, MOQ is “The most popular and friendly mocking framework for .NET”. I tend to agree with this.
Setting Up MOQ
Starting to use MOQ is easy: in the test project, install the MOQ Nuget package. This will set up your project to use MOQ. There are 2 possible ways to do this.
Using the GUI
In Visual Studio, open the Nuget Package manager (Tools > Nuget Package Manager > Manage Nuget Packages for Solution… ) and find MOQ, then install the latest stable version.
Using the NugetPackage Manager Console
If you like typing, then bring up the Nuget Package Manager Console (Tools > Nuget Package Manager > Package Manager Console). Make sure that in he Default Project, your test project is selected and then type
install-package MOQ
You will now find 2 additional references in your project references : Mocking
and Moq
.
Using MOQ in your Tests
[TestMethod()]
public void CalcDaysTestNegative()
{
var mock = new Mock<IClockService>();
mock.Setup(d => d.CurrentDate).Returns(new DateTime(1960, 1, 1));
Date dt = new Date(mock.Object);
DateTime dob = new DateTime(1967, 7, 9);
int days = dt.CalcDays(dob);
Assert.AreEqual(-2746, days);
}
The Mock
class resides in the Moq
namespace, so don’t forget to add...
using Moq;
...in your list of usings
.
I set up the mock by calling the Setup
method. In this method, I actually say: “When somebody asks you to return the CurrentDate
, then always give them January the first of 1960.”
The variable mock
now contains an implementation of IClockService
. I defined the CurrentDateproperty
to return a new DateTime(1960, 1, 1)
in 2 lines of code. This keeps my code clean because I don’t need to implement another fake class for this case. So my code stays clean and I can easily test all my border cases (such as when the 2 dates are equal).
To be complete: mock
is not an IClockService
, but this will be the mock.Object
. So I pass mock.Object
into the new Date( )
. Now I have a deterministic function for my tests!
You will appreciate MOQ even more when your interfaces become larger. When you have an interface with 20 methods, and you only need 3 methods, then you just have to mock these 3 methods, not all 20. You can also mock classes with abstract or virtual functions in the same way.
Conclusion
This is by no means a complete tutorial on how to use MOQ. You can find a tutorial at https://github.com/Moq/moq4/wiki/Quickstart written by the MOQ guys themselves. There you can find more of the power of MOQ.
I did want to show that using a mocking framework like MOQ will allow you to write simpler tests, so you have one less excuse for not writing tests!
Also now you know my date of birth, so don’t forget to send me a card!
One More Thing
I wanted to implement a simple GetAge(…)
function, which should be easy enough. But then I read this thread on StackOverflow and I decided to keep things simple and just go with CalcDays(…)
. Call me a coward.
Happy testing!!