Following on from my earlier post Could this function be unit tested without modifying it?[^] the simple answer is yes it can. In this post I will explain how.
To summarise, the function that caused the problem used the current date to make a particular calculation using
My initial approach was to pass in a default value for the date. If no date was supplied then
I had a look at the Pex and Moles[^] framework which supports unit testing by providing isolation by way of detours and stubs by allowing you to replace any .NET method with a delegate. This sounded pretty cool and I very nearly took this approach.
In the end however, I opted for a Dependency Injection approach. The benefit of this approach is that it forced me to refactor the code to make it less reliant on the environment, and that's a good thing.
In the code snippet below you will see I have defined an interface called
We then need to define a default constructor and an overloaded constructor (as we will pass in the required
So here is how we will invoke the function from the application.
And here is how we invoke the function from the unit tests. Firstly we need to define a class that implements our
Then in the test method we create an instance of this class and assign the Now property with the required value for
And that's how I managed to isolate the function so that it works both in the application without any modification to its signature, and in the unit tests whereby different values for
To summarise, the function that caused the problem used the current date to make a particular calculation using
DateTime.Now
. The original unit tests I wrote one day and all passed, then subsequently all failed the very next day as the function was returning a different result based on the current value of DateTime.Now
. My initial approach was to pass in a default value for the date. If no date was supplied then
DateTime.Now
would be used. Otherwise the supplied DateTime
argument would be used. But I wasn't keen on this approach. Supplying default arguments to functions just so they can be unit tested had a bad code smell.I had a look at the Pex and Moles[^] framework which supports unit testing by providing isolation by way of detours and stubs by allowing you to replace any .NET method with a delegate. This sounded pretty cool and I very nearly took this approach.
In the end however, I opted for a Dependency Injection approach. The benefit of this approach is that it forced me to refactor the code to make it less reliant on the environment, and that's a good thing.
In the code snippet below you will see I have defined an interface called
IDateTime
which contains one property called Now
of type DateTime
. The class ReportLibrary
then contains a reference to this interface called _datetime
. A private class called ActualDateTime
implements IDateTime
. We then need to define a default constructor and an overloaded constructor (as we will pass in the required
DateTime
in the constructor). If we create an instance of the ReportLibrary
class with no parameters (as our application will do) then the value for _datetime
is defaulted to DateTime.Now
. If we pass in a value to the constructor (as our unit tests will do) then we assign that value instead to _datetime
.namespace CoreLibrary
{///<summary>/// We use this interface for contructor injection in our unit tests./// We are essentially mocking the DateTime.Now property for unit testing.///</summary>publicinterface IDateTime
{
DateTime Now { get; set; }
}///<summary>/// Library functions used by the application///</summary>publicclass ReportLibrary
{privatereadonly IDateTime _datetime;privateclass ActualDateTime : IDateTime
{public DateTime Now { get; set; }
}//If no reference to IDateTime is passed to the constructor then default to//using the actual DateTime.Now propertypublic ReportLibrary()
{this._datetime = new ActualDateTime { Now = DateTime.Now};
}//We will inject a reference to IDateTime from our unit tests with the required value for DateTime.Now specifiedpublic ReportLibrary(IDateTime datetime)
{this._datetime = datetime;
}publicint MyFunction()
{int result;//The original line of code below//DateTime today = DateTime.Now;//This is the updated line of code DateTime today = this._datetime.Now;//rest of the calculation goes herereturn result;
}
}
}
So here is how we will invoke the function from the application.
ReportLibrary reportLibrary = new ReportLibrary();int result = reportLibrary.MyFunction();
And here is how we invoke the function from the unit tests. Firstly we need to define a class that implements our
IDateTime
interface. Define this at the top of our unit test class.
[TestClass]publicclass ReportLibraryTests
{//this goes at the top of our unit test classprivateclass MockDateTime : IDateTime
{public DateTime Now { get; set; }
}//rest of the test methods go here}
Then in the test method we create an instance of this class and assign the Now property with the required value for
DateTime.Now
.
[TestMethod]publicvoid MyFunctionTests()
{
IDateTime dateTime = new MockDateTime();//set the DateTime.Now property and inject this into the ReportLibrary constructor DateTime today = new DateTime(2016, 8, 3);
dateTime.Now = today;
ReportLibrary reportLibrary = new ReportLibrary(dateTime);int result = reportLibrary.MyFunction();
Assert.AreEqual(999, result, "Invalid result for 'MyFunction'");
}
And that's how I managed to isolate the function so that it works both in the application without any modification to its signature, and in the unit tests whereby different values for
DateTime.Now
can be supplied "There are two ways of constructing a software design: One way is to make it so simple that there are obviously no deficiencies, and the other way is to make it so complicated that there are no obvious deficiencies. The first method is far more difficult." - C.A.R. Hoare
Home | LinkedIn | Google+ | Twitter
Home | LinkedIn | Google+ | Twitter