Geeks With Blogs

@azamsharp
  • azamsharp The WWDC app says that there are new videos but there is nothing under videos!!! about 316 days ago
  • azamsharp Can I post my opinion on iOS 7 Beta or is it under NDA or something? about 316 days ago
  • azamsharp iOS 7 BETA installed successfully! about 316 days ago
  • azamsharp iOS 7 BETA installed! Now restoring! I am on NET10 which uses AT&T network. Hopefully 3G will still work! Lets c.. about 316 days ago
  • azamsharp The missing of button borders in Xcode 5 makes it hard to determine the clickable area. about 316 days ago
  • azamsharp I might wait for iOS to be released before I can put it on my device! Don't want a bricked or unstable device! about 316 days ago
  • azamsharp Android has many features that no one uses, number of versions that no one upgrades to and thousands of apps that no one pays for. about 316 days ago
  • azamsharp Maybe it is just me but the new iOS 7 UI looks like Windows Phone 8 UI! #maybeIamCrazy about 316 days ago
  • azamsharp Anyone using H20 network upgraded to iOS 7 BETA Keep me updated if you face any problems. about 316 days ago
  • azamsharp @merowing_ You already downloaded it! I cannot even load the developer's website! :( about 316 days ago

AzamSharp Some day I will know everything. I hope that day never comes.

Mock object is basically a mirage of the real object as they posses the same qualities by don't do anything. Mock objects really shines when working with some entity that continuously changes like time, temperature, air speed etc. In this post I will introduce mock objects and how can they be useful when unit testing such entities.

I took the idea from a great article published on AspAlliance. The article "Beginning to Mock Using Rhino Mocks and MbUnit" is written by Ben Hall. The idea is that we are testing that your method returns the correct image. The correctness of the image depends on the time of the day. So, if it is day time then "sun.jpg" is returned and if it is night time then "moon.jpg" is returned. Let's first see the implementation without using the Mock objects.

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

The above method is used to test for the image during the day time. Let's check out the implementation of the ImageOfTheDayService.GetImage method.

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

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

            return "moon.jpg";      
        }

The problem is that you can only test the day time result during the day and the night time result during night. This is inconvenient. You can hack the implementation of your tests and force the day time and night time to happen. Check out the implementation below:

 [Test]
        public void should_return_sun_image_when_it_is_day_time()
        {
            DateTime dt = DateTime.Parse("02/02/02 5:00 AM");           

            int hour = dt.Hour;                      

            int lessHour = 0;

            if (hour < 6)
                lessHour = 15 - hour;

            if (hour > 21)
                lessHour = 15 - hour;

            string imageName = ImageOfTheDayService.GetImage(dt.AddHours(lessHour));
            Assert.AreEqual(imageName, "sun.jpg");
        }

        [Test]
        public void should_return_night_image_when_it_is_night_time()
        {
            int hour = DateTime.Now.Hour;
            int lessHour = 0;

            if (hour < 21)
            {
                lessHour = 21 - hour;
            }

            string imageName = ImageOfTheDayService.GetImage(DateTime.Now.AddHours(lessHour));
            Assert.AreEqual(imageName, "moon.jpg");
        }

In the should_return_sun_image_when_it_is_day_time test I am using 5:00 AM as the start time. The problem is that 5:00 AM is still night (according to the demo application). In order to a successful test I need to provide the day time. So, I do some funky stuff and crank the time to 3:00 PM which is the time during the day. Now, I test my GetImage method using the new fake time.

The funky hack makes the test pass but leaves behind ugliness in the test methods. Now, let's introduce the Mock objects to clear out this mess. I am using Moq framework to create my mock objects but you can use any framework you like. First, I need to create an interface for the DateTime which I can feed to the Moq framework to return me a mocked object.

 public interface IDateTime
    {
        int GetHour();
    }

Now, the GetImage method of the ImageOfTheDayService will take the IDateTime as the parameter instead of the DateTime.

 public static string GetImage(IDateTime mock)
        {
            int hour = mock.GetHour();

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

            return "moon.jpg";           
        }

Now, let's check out the test using mock objects.

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

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

        [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));
        }

The test becomes much simpler now. All we are saying is that we expect a call on the "GetHour()" method of the IDateTime interface. The method will return "15" (day test). We are not concerned about what is the current time of the day since we are putting expectations and results. Finally, we pass the IDateTime to the GetImage method and compares the output with our expected results.

Posted on Sunday, April 27, 2008 11:08 AM | Back to top


Comments on this post: Understanding Mock Objects

# re: Understanding Mock Objects
Requesting Gravatar...
Hello anonymous blogger,

Ideally, your time service would expose operations which directly reflect the interests of its clients. In this case, the concern is whether it is day time or night time.

The calculation of whether it is day or night is an orthogonal concern of the image generation and therefore should be moved out of the GetImage method.

GetImage wants to know whether it is day or night, and so this is the semantics of the interface that ITime should expose.

interface ITimeService
{
public bool IsDayTime(DateTime time)
}

class ImageThing
{
public static string GetImage(ITimeService time)
{
if (time.IsDayTime(DateTime.Now))
{
return "sun.jpg";
}
else
{
return "moon.jpg";
}
}
}

The call to DateTime.Now might ultimately need to be a member of ITimeService at some point if it ends up needing to be mocked, but at this point, this implementation is the simplest thing that could possibly work based on my current understanding of the requirements and the needs of the implementation.

There are a few alternative designs that would suit here, all of which would not have required creating an adapter for DataTime, and would ultimately lead to rich, intent-revealing and natural API for your domain.

Ultimately, I would be suspect of the method signature:

public static string GetImage(ITimeService time)

It has two design smells:
- It's static
- It accepts a service interface as its argument (method injection)

The method might be perfectly fine, but it's on yellow alert for the time being.
Left by Scott Bellware on Apr 27, 2008 2:16 PM

# re: Understanding Mock Objects
Requesting Gravatar...
Hi Scott,

How are you doing?

>> Hello Anonymous Blogger
Well, you should have said "Hello Guy with whom I shared the taxi ride during the MVP summit :)."

But anyways, I agree with your comments. The GetImage method should not be concerned about checking whether it is day or night but only about returning the correct image (following the SRP).


Left by Mohammad Azam on Apr 27, 2008 2:37 PM

# re: Understanding Mock Objects
Requesting Gravatar...
Using Typemock will allow you to use Extension methods to make it even cleaner.

public bool IsDayTime(this DateTime time) {...}

public static string GetImage()
{
if (DateTime.Now.IsDayTime())
{
return "sun.jpg";
} else {
return "moon.jpg";
}
}

Now your tests can be:

[Test]
public void MOCKING_should_return_night_image_when_it_is_night_time()
{
// System will think that it is night time
using (Recorder r = new Recorder())
{
r.ExpectAndReturn(
DateTime.Now.IsDayTime(),
false);
}

Assert.AreEqual("moon.jpg", ImageOfTheDayService.GetImage(mock.Object));
}
Left by Eli Lopian on Apr 28, 2008 8:46 PM

# re: Understanding Mock Objects
Requesting Gravatar...
Hi Eli,

I like your that approach with TypeMock.

Scott, I think you are right in the fact that this logic is not in the correct place, the example was more to demostrate mocking in general.

For me Eli's extension method seems to be the most logical place in this scenario.

Cheers

Ben
Blog.BenHall.me.uk
Left by Ben Hall on Apr 29, 2008 10:46 AM

# re: Understanding Mock Objects
Requesting Gravatar...
Uuuh, whats that strange purple symbol in front of the comments. Looks almost like something German.
Left by No-Offence on Apr 30, 2008 4:19 AM

# re: Understanding Mock Objects
Requesting Gravatar...
Hi Mohammad,

I don't know where the images in front of the comments are comming from. Maybe generated or something but the image in front of Scott's comments look like a inverse swastika.
Left by redgreenrefactor on Apr 30, 2008 6:49 AM

# re: Understanding Mock Objects
Requesting Gravatar...
Hi,

Well, I am not sure where the images are coming from. I guess the images are part of the SubText Framework and are used when the commenter does not have a proper picture.
Left by Mohammad Azam on Apr 30, 2008 6:51 AM

# re: Understanding Mock Objects
Requesting Gravatar...
Hi,

What I usually watch for in my tests is excessive setup. Here, you have to do a lot of time-related setup in order to return one of two images. It's perfect for an integration test, but for a unit test you just need a boolean value. Having realized that, I would write a test for ImageProvider.GetImage(bool IsDayTime) and another for DayService.IsDayTime(this DateTime time).

My point is, sometimes we need neither DI nor mocks. We can have two classes totally decoupled, and unit tests as simple as they can be. If we make testability our guide to a better design, we often end with several small independent classes that can be tested without mocks.

Still, mocking is a very powerful technique, and there are times when you can't do without it.
Left by ulu on May 04, 2008 8:35 AM

Your comment:
 (will show your gravatar)
 


Copyright © Mohammad Azam | Powered by: GeeksWithBlogs.net | Join free