Understanding Mock Objects: an alternate solution

In AzamSharp’s recent post Understanding Mock Objects, he poses a problem of testing with volatile data.  His example extends on an article on AspAlliance, which exhibits the same problems with its solution.  Suppose I have an image service that returns images based on the time of day:

public static class ImageOfTheDayService
{
    public static string GetImage(DateTime dt)
    {
        int hour = dt.Hour;

        if (hour > 6 && hour < 21) return "sun.jpg";

        return "moon.jpg";
    }
}

The initial test uses the current date and time to perform the test:

[Test]
public void should_return_sun_image_when_it_is_day_time()
{
    string imageName = ImageOfTheDayService.GetImage(DateTime.Now);
    Assert.AreEqual(imageName, "sun.jpg");
}

Since DateTime.Now is non-deterministic, this test will pass only some of the time, and will at other times.  The problem is that this test has a dependency on the system clock.  AzamSharp’s solution to this problem was to create an interface to wrap DateTime:

public interface IDateTime
{
    int GetHour();
}

Now the ImageOfTheDayService uses IDateTime to determine the hour:

[Test]
public void MOCKING_should_return_night_image_when_it_is_night_time()
{
    var mock = new Mock<IDateTime>();
    mock.Expect(e => e.GetHour()).Returns(21); // 9:00 PM

    Assert.AreEqual("moon.jpg", ImageOfTheDayService.GetImage(mock.Object));
}

I really don’t like this solution, as the test had the external non-deterministic dependency, not the image service.

Alternative solution

Here’s another solution that doesn’t use mocks, and keeps the original DateTime parameter:

[Test]
public void should_return_night_image_when_it_is_night_time()
{
    DateTime nightTime = new DateTime(2000, 1, 1, 0, 0, 0);

    string imageName = ImageOfTheDayService.GetImage(nightTime);
    Assert.AreEqual(imageName, "moon.jpg");
}

Note that I eliminated the dependency on the system clock by simply creating a DateTime that represents “night time”.  Another test creates a “day time” DateTime, and perhaps more to fill in edge cases.  Instead of creating an interface to wrap something that didn’t need fixing, we used DateTime exactly how they were designed.  DateTime.Now is not the only way to create a DateTime object.

Solving a non-deterministic test with mocks only works when it’s the component under test that has the non-deterministic dependencies.  In the example AzamSharp’s example, it was the test, and not the component that had the non-deterministic dependency.  Creating the DateTime using its constructor led to both a more readable test and a more cohesive interface for the image service.

It’s easy to believe everything is a nail if all you want to use is that shiny hammer.  Keep in mind the purpose of mocks: to verify the indirect inputs and outputs of a component, not to fix every erratic test under the sun.

Related Articles:

Post Footer automatically generated by Add Post Footer Plugin for wordpress.

About Jimmy Bogard

I'm a technical architect with Headspring in Austin, TX. I focus on DDD, distributed systems, and any other acronym-centric design/architecture/methodology. I created AutoMapper and am a co-author of the ASP.NET MVC in Action books.
This entry was posted in Uncategorized. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • http://www.elegantcode.com Chris Brandsma

    The problem, as I see it, is that is not code that 90% of developers would have written. They would have written it like this:

    public static class ImageOfTheDayService
    {
    public static string GetImage()
    {
    DateTime dt = DateTime.Now;
    int hour = dt.Hour;

    if (hour > 6 && hour < 21) return “sun.jpg”;

    return “moon.jpg”;
    }
    }

    not knowing they had just created a dependency on DateTime. Now when they want to test it they realize that there is a problem because of the DateTime.Now.

    Faced with that problem only a few developers would rewrite their code to look like yours, a few others would discover TypeMock and do it that way, and the vast majority would just give up.

  • http://neilmosafi.blogspot.com Neil Mosafi

    I agree with the author. DateTime is a value type, what possible need could there be to mock it?

    AzamSharp’s article even posted a solution that uses DateTime.Parse and then proceeded to utterly obfuscate it by adding hours to it within his test! Maybe this was to make the test seem so complicated that he could then justify abstracting something that didn’t need abstracting. This is madness I tells ya!

  • http://devlicio.us Derik Whittaker

    In your example you do not need to mock the date/time value because that is something you can predefine and in turn have known inputs against know output. But what you do not mention is that you would want to use mocks when calling the image server in any test other then actually interaction tests designed to test the images service.

  • http://jimmybogard.lostechies.com Jimmy Bogard

    @Derek

    Which would be hard as the image server in the original example is a static class. Just all around a bad example for mocks.

  • Jeremy Gray

    Pulling the time out into an argument is just passing the buck. Now the caller ends up calling DateTime.Now, unless you introduce an argument into the caller and then the caller’s caller ends up calling DateTime.Now. Unless you like giant long chains of unnecessary arguments that just avoid the problem, introducing a clock service is a well-established practice and is the right thing to do.

    That said, I certainly wouldn’t pass the clock service into the GetImage call. I’d feed it into the ImageOfTheDayService through other means, whether they be via a Service Locator or through some dependency injection.

  • http://chadmyers.lostechies.com Chad Myers

    When making simple decisions based on the value of the value type, it should just be passed in, agreed.

    But when building time-triggered event systems or systems that need to grab the current date/time deep down somewhere, it helps to have the system clock wrapped as a service.

    This makes it easier to wire things up via an IoC container also to the point there you’d never see ImageOfTheDayService being created such that you’d have to care what ISystemClock was (or IDateTimeService).

    I usually end up wrapping DateTime.Now through ISystemClock and most of the people I know doing DI/IoC have also done this because you can’t keep passing DateTime’s around all over the place all the time.

    In fact, most projects I start now I usually just add ISystemClock, IFileSystem, and, if winforms, IMessageBoxCreator because there hasn’t been a time when I didn’t end up needing those for some reason or another.

  • http://jimmybogard.lostechies.com Jimmy Bogard

    @chadmyers

    Yeah, we’ll do the ISystemClock quite a bit, when the component has a dependency to DateTime.Now.

  • Lucas Goodwin

    I have a different take. If the code is relying on the datetime to do time specific things then yes, pass ‘er in like above. It’s an external dependency and is perfectly reasonable to advertise as such via the interface.

    However, usually, these kinds of tests are for verifying datamappers, builders, etc. You don’t really care what the time is, only that they’re being set. It’s an interaction test. The only time I can see caring explicitly about the specific date and time is if you were writing your own datetime object.

    As such, I just do “toshortdatestring” on my expected and actual and call it good. You gotta question what you’re really trying to test.

  • http://jimmybogard.lostechies.com Jimmy Bogard

    @Lucas

    The _only_ reason a component should mock out DateTime with an ISystemClock is if it uses “DateTime.Now”. Stubs and Mocks are meant for indirect inputs, when the real implementation depends on the execution context. Would you create an “IInt32″ for “int.ToString()”?

    I understand the “question what you’re trying to test” statement. What your path leads us down is a road where every object with a method needs to have a backing interface. That leads toward brittle tests. Suppose you change your implementation to use “ToLongDateString”? Do you want your test to fail because of that?

  • http://chadmyers.lostechies.com Chad Myers

    Yeah, DateTime.Now is really a non-determinant external dependency (system clock) that’s cleverly hidden in a value object (System.DateTime).

    I definitely would NOT mock anything on DateTime except the non-determinant stuff (Now, UtcNow, etc).

  • Lucas Goodwin

    @bogardj

    I wasn’t very clear in my use of terms above. I apologize. I’m not saying wrap Datetime in an interface. That way lies insanity (as you pointed out). I’m saying the method’s parameters (interface) being refactored to rely on an external dependency like DateTime makes sense, as your solution shows.

    I’m just saying that I’ve never experienced a test were I really cared what the time was to the millisecond. In the last year and half of unit tests (when I started doing this test hack, and I agree, it is, but it works) I’ve never experienced a test maintinance issue.

    “Now” is one of those issues where I feel “good enough” is a reasonable attitude to take.

  • http://colinjack.blogspot.com Colin Jack

    @bogardj
    You are bang on, passing in a predefined date time is a good solution and you’d only need to go to the other solution if it was required (as you say where it has a dependency on DateTime.Now).

    Also it always slightly irks me having to wrap DateTime, especially if its just using something like IDateTime or IClock. You sometimes don’t have much of a choice though, and in some cases you may be able to add extract functionality to the abstraction.

  • PandaWood

    >> What is not code that 90% of developers would have written

    I’m not sure what your point is here really. I’m with the author but I wouldn’t really care to have a guess as to how many other developers would ‘give up’. Maybe after reading this blog, some of those 90% won’t be doing it anymore… ?