Mark Needham

Thoughts on Software Development

Coding: API readability/testability

with 9 comments

About a month ago or so I described how we did some work to ensure that we were calling a class the same way in our tests as in our production code and while I think that was a good choice in that situation we came across a similar problem this week where we weren’t so sure.

The piece of code in question was being used to create the view model for a page and one of the pieces of data that we wanted to show on this page was the date on which something would be valid which is currently today’s date.

We were working with some code that looked a bit like this:

public class SomeRandomModel
{
	...
 
	public static SomeRandomModel CreateForSomeSituation(string value1, string value2)
	{
		return new SomeRandomModel(value1, value2);
	}
 
	public string SomeDate()
	{
		return DateTime.Today.ToDisplayFormat();
	}
}
public static class DateTimeExtensions 
{
	public static string ToDisplayFormat(this DateTime aDateTime)
	{
		return String.Format("{0:MMM d, yyyy}", aDateTime)
	}
}

Initially we put the following test around the code:

[Test]
public void ShouldConstructModelForSomeSituation()
{
	var model = SomeRandomModel.CreateForSomeSituation("", "");
 
	...
 
	Assert.AreEqual(DateTime.Today.ToDisplayFormat(), model.SomeDate()); 
}

The problem with this test is that it could theoretically fail if the ‘DateTime.Today’ in the test and the ‘DateTime.Today’ in the code were fired near enough to midnight that they returned different days.

It’s not quite as big a problem as we would have if we were actually comparing the equality of the two dates but it’s still not great to write a test which might fail sporadically.

We therefore need to find a way to control the input to the code so that we can test the output.

The problem is that the date is always going to be today at the moment so it seems to unnecessarily complicate the ‘CreateForSomeSituation’ method if we had to pass in ‘DateTime.Today’ as a parameter.

Our current solution was therefore to create a test only method which takes in a date and then get the original method to delegate to the test only one while passing in ‘DateTime.Today’ as the extra parameter.

public class SomeRandomModel
{
	private readonly DateTime aDateTime;
	...
 
	public static SomeRandomModel CreateForSomeSituation(string value1, string value2)
	{
		return CreateForSomeSituation(value1, value2, DateTime.Today);
	}
 
	public static SomeRandomModel CreateForSomeSituationForTest(string value1, string value2, DateTime aDateTime)
	{
		return new SomeRandomModel(value1, value2, aDateTime);
	}
 
	public string SomeDate()
	{
		return aDateTime.ToDisplayFormat();
	}
}

Our test now becomes:

[Test]
public void ShouldConstructModelForSomeSituation()
{
	var model = SomeRandomModel.CreateForSomeSituationForTest("", "", new DateTime(2009, 10, 10));
 
	...
 
	Assert.AreEqual("10 Oct 2009", model.SomeDate()); 
}

We can now specify our expectation a bit more cleanly since we aren’t tied to ‘DateTime.Today’.

It helped solve our problem reasonably well but it still seems a bit weird to me to have ‘test only’ code but I’m not sure what a better solution would be.

Written by Mark Needham

October 10th, 2009 at 12:21 am

Posted in Coding

Tagged with ,

  • http://www.randomfocus.net/ Adam Scott

    The alternative is to stub what DateTime.Today returns. However I realise that stubbing static calls is not trivial, so I guess the question becomes – how about injecting a Clock object, rather than relying on the static call?

  • Ryan Roberts

    I use a ..static DomainTime.Instance shim to control datetime in tests.

    Ends up with something like

    using(DomainTime.Is(new(DateTime(2003,10,10))
    {
    var model = SomeRandomModel.JustTheUsualMethod();
    DomainTime.HasBeen(new TimeSpan(0,0,0,1));

    Assert.AreEqual(..)
    }

    Where the using scope controls whether the DomainTime class returns real times or test values.

  • http://www.markhneedham.com Mark Needham

    @Adam – that was the other thing we were debating – forgot to mention that! Thinking was maybe a clock was a bit overkill at the moment because we only have this one test which is dependent on date. In general though I like the idea of the clock.

    @Ryan – so do you use ‘DomainTime’ in your code instead of ‘DateTime’ with that approach?

  • Ryan Roberts

    Yes, unfortunately. It’s not a real proxy. A clock object would be more elegant, but then you get into issues around service injection into domain objects. An issue I blithely ignored by using a static dependency :)

  • Pingback: Tweets that mention Coding: API readability/testability at Mark Needham -- Topsy.com

  • Phil Cleveland

    What about making the the test method (CreateForSomeSituationForTest) internal, so that the API will not be polluted? Of course you would have to setup your test fixture to have access to internal methods with this approach.

  • http://jonathan-oliver.blogspot.com Jonathan

    We use something similar to Ryan’s approach, but based upon the code he’s got, I think I like his solution better. It’s simply, elegant, testable, and doesn’t require injection into your entity objects.

  • http://jonathan-oliver.blogspot.com/2009/10/ddd-entity-injection-and-mocking-time.html Jonathan

    @Ryan — I just blogged about your particular solution for controlling “now”. What does the “HasBeen” method do in your above example. Also, do you have any other interesting behavior/methods on your DomainTime instance?

  • Pingback: DDD: Entity Injection and Mocking Time