Thursday, April 5, 2012

Mock C# DateTime.Now in NUnit tests using Moles

Thursday, April 05, 2012 Posted by Andre Broers , , , , , 11 comments
We needed to test code which uses the current date. To create unit tests it is desirerable to test with different dates. To do this we needed something to mock .net class DateTime. First thing that came to mind was to create our own interface to get the system time and implement different versions. But what about dates in included assemblies etc.etc. We ran into Moles. Unfortunatly it’s a Microsoft proprietary library which can only be obtained with an MSDN subscription.

The installer can be found here.

First thing is to install it.

We also need to install nunit. I will later on install nunit via nuget, but we need the full install to get the console-runner.exe app to run the test assembly. Install nunit from here.

Now open Visual Studio 2010 and create a new solution MyTests with a new Class Library Project MyTests. Be sure that the target is Any CPU to prevent problems with the different testrunners later on.

Install the nunit via nuget:
PM> install-package nunit
Successfully installed 'NUnit 2.6.0.12054'.
Successfully added 'NUnit 2.6.0.12054' to MyTests.

PM>

Now we have to create a Moles file on the mscorlib assembly (This is the one DateTime sits in). Unfortunatly this assembly isn’t shown in the referenced assemblies in the solution explorer in visual studio. Therefor we pick the System.dll to start with.

Now right click on the referenced System.dll and select Add Moles Assembly. An xml file System.moles is created in our project. We now need to rename it to mscorlib.moles . When you open it up in the editor it will look like this:
<Moles xmlns="<a href="http://schemas.microsoft.com/moles/2010/&quot;">http://schemas.microsoft.com/moles/2010/"</a>>
  <Assembly Name="System" />
</Moles>

All we have to do is change the Assembly Name from System to mscorlib:
<Moles xmlns="<a href="http://schemas.microsoft.com/moles/2010/"">http://schemas.microsoft.com/moles/2010/"</a>>
  <Assembly Name="mscorlib" />
</Moles>

We also need to edit the AssemblyInfo.cs file. Add the following line to the bottom of the file:
[assembly: MoledType(typeof(System.DateTime))]

And add the following lines to the using list:
using Microsoft.Moles.Framework;

The assembly will automatically be referenced the first time we build our project.

Now it’s time to create our test class:

Create the test class MyDateTimeTest.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Moles.Framework;
using NUnit.Framework;
using System.Moles;

namespace MyTests
{
  [TestFixture]
  public class MyDateTimeTest
  {
    [Test]
    public void DateTimeTest()
    {
      using (MolesContext.Create())
      {
        MDateTime.NowGet = () => new DateTime(2001, 1, 1);
        MDateTime.TodayGet = () => (new DateTime(2001, 1, 1)).Date;
        Assert.AreEqual(new DateTime(2001, 1, 1), DateTime.Now);
        Assert.AreEqual(new DateTime(2001, 1, 1), DateTime.Today);
      }
    }
  }
}

In line 7 we add a using statement for our new System.Moles assembly where the MDateTime.NowGet and MDateTime.TodayGet are located. The first capital M in these properties is a Moles addition and the Get at the end also to show it is a get property we are redefining. Always use a delegate function to return the data.

In line 17 we created the MolesContext. This means that inside this using the DateTime will be overruled. Outside this context the normal DateTime will work.

Ok now it time to build the solution and start a console to test the Test Assembly.

Start a console and change to debug directory

now start the following command:

"c:\Program Files\Microsoft Moles\bin\moles.runner.exe" MyTests.dll /r:"c:\Program Files (x86)\nunit 2.6\bin\nunit-console.exe"


It will give the following result:

Microsoft Moles Runner v0.94.51023.0 -- <a href="http://research.microsoft.com/moles">http://research.microsoft.com/moles</a> -- .
NET v4.0.30319
Copyright (c) Microsoft Corporation 2007-2010. All rights reserved.

instrumenting...started
NUnit-Console version 2.6.0.12051
Copyright (C) 2002-20011 Charlie Poole.
Copyright (C) 2002-2004 James W. Newkirk, Michael C. Two, Alexei A. Vorontsov.
Copyright (C) 2000-2002 Philip Craig.
All Rights Reserved.

Runtime Environment -
OS Version: Microsoft Windows NT 6.1.7600.0
CLR Version: 4.0.30319.261 ( Net 4.0 )

ProcessModel: Default    DomainUsage: Single
Execution Runtime: net-4.0
.
Tests run: 1, Errors: 0, Failures: 0, Inconclusive: 0, Time: 0,6520373 seconds
Not run: 0, Invalid: 0, Ignored: 0, Skipped: 0


As we can see our test run shows no errors. Just what we wanted.

11 comments:

  1. Do you know that we have developed a programming language for testing: Visual T#?

    It's free, accessible to anybody and includes mocking capabilities (and many more).

    Thus, once Visual T# installed, you only have to write your test:

    using System;

    namespace MyTests
    {
    testclass
    {
    test
    {
    DateTime.$Now { return new DateTime(2001, 1, 1) };

    runtest DateTime now = DateTime.Now;

    assert now.Equals(new DateTime(2001, 1, 1));
    }
    }
    }

    ReplyDelete