Beginning to Mock with Rhino Mocks and MbUnit - Part 1
 
Published: 13 Sep 2007
Abstract
In this article Ben provides a brief overview of Rhino Mocks mock object framework for the .NET platform with the help of an example. The author also discusses what a mock object is and when a mock object might be required.
by Ben Hall
Feedback
Average Rating: This article has not yet been rated.
Views (Total / Last 10 Days): 43657/ 69

Introduction

This is the first in a series of articles covering the Rhino Mocks mock object framework for the .NET platform. The aim of this series is to provide you with an understanding of how mock objects are used, how they can improve the quality of your unit tests and how mock objects can make the difficult to test sections of your application simpler to test.

In this first part I am going to cover what a mock object is and when a mock object might be required. I also give an example of using mock objects within your unit testing and show how mock objects can significantly increase the quality of your tests.

What is a mock object?

A mock object is generally used as a stand-in, or replacement, for a real object while the system is being unit tested. The main purpose of using a mock object is to allow our tests to be more focused, self contained, predictable and reliable. By having our unit tests more isolated and predictable we can identify the cause of the failure in less time and false negatives (tests which fail but should pass) are reduced.

An example of when a mock object might be used is when a feature in your system is required to return different results based on the current time of day. Given this requirement, how could it be tested? It would have a number of problems, for example you would have to have different test logic depending on the time of day the tests where executed and worse, only being able to execute the test at certain times of the day in order for it to execute the conditional logic being tested. Identifying the real reason why a test has failed would also become a problem as it could be because of the code or because of the time the test was executed.

This is where mock objects become useful. A mock object would allow us to replace the unpredictable functionality of obtaining the time, and replace it with pre-setup logic with known values which we could test against. We could then write and configure different tests to take into account the different requirements without having to worry about when or where the tests are actually executed. This makes the tests more useful as they could be run and instantly report back if there was a problem.  As a result, tests can be run more often and problems are likely to be fixed in a much shorter time as one of the external dependencies which had the potential to cause problems has been removed.

Other reasons why you might want to use mock objects in your unit tests include:

·         Access to the real object is slow because of database calls or long calculations.

·         The real object uses a call back.

·         The real object requires access to external resources which are unavailable.

·         The real object has not finished being developed.

Tool Support

There are a number of tools available to support mocking of objects and they are generally in one of two categories - static or dynamic. Static mock tools generate mock implementations as source code which is compiled with the test suite, while dynamic mock frameworks create the mock implementations at runtime.

Rhino Mocks is a dynamic mock object framework for the .NET platform which allows developers to create mock objects and verify the interactions while unit testing. Rhino Mocks is a very powerful framework, in this part I will only discuss how to get started.

Rhino mocks is an open source framework created by Ayende Rahien and is available to download from the official web site. There are alternative frameworks available such as EasyMock.Net and NMock.

Rhino mocks works with all the .NET unit testing frameworks currently available. For this series I will be using MbUnit, which can be downloaded from www.MbUnit.com, as it has some excellent features that improve the unit tests.

A Mocking Example

To start with, let us solve the dilemma set out at the beginning - testing against the system time. A method, GetImageForTimeOfDay(), should return a filename to a image based on the time of day it currently is; for example, sun.jpg for daytime and a moon.jpg for night time.

This is how the tests might look if we were not using mock objects. I have cut down a lot of the code which would actually be required, for example taking into account timezones and time of year.

Listing 1

[Test] 
public void DaytimeTest() 
{ 
   int currentHour = DateTime.Now.Hour; 
  
   if (currentHour > 6 && currentHour < 21) 
   { 
      string expectedImagePath = "sun.jpg"; 
      ImageManagement image = new ImageManagement(); 
      string path = image.GetImageForTimeOfDay(); 
      Assert.AreEqual(expectedImagePath, path); 
   } 
   else 
   { 
      Assert.Ignore("Can only be tested during the day"); 
   } 
} 
  
[Test] 
public void NighttimeTest() 
{ 
   int currentHour = DateTime.Now.Hour; 
  
   if (currentHour < 6 || currentHour > 21) 
   { 
      string expectedImagePath = "moon.jpg"; 
      ImageManagement image = new ImageManagement(); 
      string path = image.GetImageForTimeOfDay(); 
      Assert.AreEqual(expectedImagePath, path); 
   } 
   else 
   { 
      Assert.Ignore("Can only be tested at night"); 
   } 
} 

The method could be implemented like this:

Listing 2

public string GetImageForTimeOfDay() 
{ 
   int currentHour = DateTime.Now.Hour; 
  
   if (currentHour > 6 && currentHour < 21) 
      return "sun.jpg"; 
   else 
      return "moon.jpg"; 
} 

This is far from ideal as we can only ever run one test at a time as they can only be run at certain points in the day.  If we change the code, we can only test one part of the actual requirement, unless we modify the system clock. Having difficult to execute tests is just one reason why we might stop running the tests altogether. How can we trust the application even works?

By using a mock object and abstracting away from DateTime.Now.Hour we will be able to have much more reliable tests.  In order to be able to use mock objects, we need to a use an interface design for obtaining the time. Rhino Mocks then uses this interface to create the mock implementation of the object which allows us to call the methods on the interface just like we would with a real implementation.

We then use parameter injection to define which implementation should be used within the method. 

When using mock objects, the tests would look like this.

Listing 3

[Test] 
public void DaytimeTest() 
{ 
   MockRepository mocks = new MockRepository(); 
   IDateTime timeController = mocks.CreateMock<IDateTime>(); 
  
   using (mocks.Record()) 
   { 
      Expect.Call(timeController.GetHour()).Return(15); 
   } 
  
   using (mocks.Playback()) 
   { 
      string expectedImagePath = "sun.jpg"; 
      ImageManagement image = new ImageManagement(); 
      string path = image.GetImageForTimeOfDay(timeController); 
      Assert.AreEqual(expectedImagePath, path); 
   } 
} 
  
[Test] 
public void NighttimeTest() 
{ 
   MockRepository mocks = new MockRepository(); 
   IDateTime timeController = mocks.CreateMock<IDateTime>(); 
   using (mocks.Record()) 
   { 
      Expect.Call(timeController.GetHour()).Return(1); 
   } 
  
   using (mocks.Playback()) 
   { 
      string expectedImagePath = "moon.jpg"; 
      ImageManagement image = new ImageManagement(); 
      string path = image.GetImageForTimeOfDay(timeController); 
      Assert.AreEqual(expectedImagePath, path); 
   } 
} 

With the implementation for the system now being:

Listing 4

public interface IDateTime 
{ 
   int GetHour(); 
} 

 

public class ImageManagement 
{ 
   public string GetImageForTimeOfDay(IDateTime time) 
   { 
      int currentHour = time.GetHour(); 
  
      if (currentHour > 6 && currentHour < 21) 
      { 
         return "sun.jpg"; 
      } 
      else 
      { 
         return "moon.jpg"; 
      } 
   }
}  

Now we have a set of useful tests which can be executed no matter what time it is, however, the mock syntax may look very different to you.

In the first line we are defining a MockRepository which is the main interaction with the Rhino Mocks framework.

Listing 5

MockRepository mocks = new MockRepository(); 

We then define our mock object. There are two methods for creating the mock, one is CreateMock<> while the other is DynamicMock<>. According to the documentation, CreateMock has strict semantics, meaning if a call is made on the mock object which it was not expecting then it will throw an exception.  DynamicMock has dynamic semantics where unexpected calls are accepted with a null/zero value being returned and no exception is thrown.

Listing 6

IDateTime timeController = mocks.CreateMock<IDateTime>(); 

Next, we enter recording mode for the mock object. This is an important stage where we define what we want the mock object to do. We define the calls we expect to be made on the object and the values which should be returned. This is how we can create a known state for our system as everything is defined in recording mode. In this example we are saying that we expect that the GetHour() method will be called on our mock implementation (timeController) and that this should always return the value 15 to the calling code. 

Listing 7

using (mocks.Record()) 
{ 
   Expect.Call(timeController.GetHour()).Return(15); 
} 

From a Test Driven Development (TDD) approach, this encourages us to focus on the design a lot more upfront as we define all of the method calls and the return values.

After we have defined all of our expectations we enter Playback mode.  In this mode we write the unit test as normal.

Listing 8

using (mocks.Playback()) 
{ 
   string expectedImagePath = "sun.jpg"; 
   ImageManagement image = new ImageManagement(); 
   string path = image.GetImageForTimeOfDay(timeController); 
   Assert.AreEqual(expectedImagePath, path); 
} 

Notice how the GetImageForTimeOfDay() method now takes in the IDateTime object as a parameter. This approach allows us a lot more flexibility and allows us to define which implementation, either the mock object or real, at runtime it should use instead of the method deciding for us.  If we wanted to clean up the code for production, we could overload the method with no parameters, which simply initializes the default implementation and passes it in as an argument.

Finally, now we have written the test, we can write the code to make them pass.

Listing 9

public string GetImageForTimeOfDay(IDateTime time) 
{ 
   int currentHour = time.GetHour(); 
  
   if (currentHour > 6 && currentHour < 21) 
   { 
      return "sun.jpg"; 
   } 
   else 
   { 
      return "moon.jpg"; 
   } 
} 
  
public class DateTimeController : IDateTime 
{ 
   public int GetHour() 
   { 
      return DateTime.Now.Hour; 
   } 

We are still calling DateTime.Now.Hour, however our GetImageForTimeOfDay() is no longer dependant on this.  

An application could then look like this:

Listing 10

static void Main(string[] args) 
{ 
   ImageManagement image = new ImageManagement(); 
   string path = image.GetImageForTimeOfDay(new DateTimeController()); 
   Console.WriteLine(path); 
   Console.ReadLine(); 
} 

Hopefully from this, you can see that using Rhino Mocks greatly increases the capabilities of the tests which we are writing, allowing us to replace the hard to test components. Also, mock objects have improved the design of the system by encouraging us to program against interfaces, one of the core OO design rules, and abstracting away from the core framework. If we have to change the way we handle obtaining the time, maybe from a external time server, we only have to change the internal method in our DateTimeController.

What are the limitations?

Like with any approach there are certain limitations when using mock objects. At the moment, when using Rhino Mocks, you cannot create a mock object from a sealed class, you cannot create a mock object from a private interface and you cannot intercept calls to non-virtual methods.

Also, trying to mock part of the .NET Framework is not recommended.  Instead, create a wrapper around the calling code like we did here and abstract away from the .NET implementation as you will find it much easier to setup the mock environment and test against the code.

Downloads

Summary

Hopefully, this has been a useful insight into the world of mock objects and in particular Rhino Mocks. We have covered what a mock object is, the supporting tools, an example of using Rhino Mocks to replace the code which depends on the system time at runtime and covered the limitations of mocks.

In the next article in the series I plan to discuss the alternatives to mock objects and how to use mock objects to replace your data access layer.



User Comments

Title: "Program against interfaces"   
Name: Rogério Liesenfeld
Date: 2009-10-06 5:01:32 PM
Comment:
What exactly is meant here by "program against interfaces, one of the core OO design rules"?

Creating an IDateTime interface with a single DateTimeController implementation class is absolutely NOT what was intended by the GoF book (Design Patterns) when they said "program to interface, not an implementation".

That "core OO design rule" is about something else: polymorphism; and it's really only applicable in the context of reusable OO software, specifically for dependencies between subsystems. Not at all the case for the example in this article.
Title: Question   
Name: bangi
Date: 2009-05-06 9:37:40 AM
Comment:
Is it possible to mock an object to is called by the method that I am calling. Eg. 1SomeInterface has a method called GetUsers. GetUsers calls a method called findusers which belongs to a Interface IDataAccess. Is it correct to make a mock object for IDataAccess in my Test class hoping that when I call ISomeInterface when ISomeInterface gets to the IDataAccess.findusers() the mock version will be user instead of the real method.
Title: Thanks   
Name: dotnetguts
Date: 2008-10-27 2:23:56 PM
Comment:
Thanks, Good Information.

DotNetGuts
http://dotnetguts.blogspot.com
Title: Excellent   
Name: Iran
Date: 2008-09-13 7:17:49 AM
Comment:
Thanks a lot Ben for providing a simple start up guide for Rhino mocks
Title: Stubs v Mocks   
Name: Ben Hall
Date: 2008-05-27 6:49:28 AM
Comment:
\
Title: I recomended this book   
Name: Carlos
Date: 2008-05-27 6:04:34 AM
Comment:
This post is very well, but are confused concepts(STUBS-MOCKS)
I recommend reading this book is really good.

http://www.manning.com/osherove/
Title: Diference Stubs and Mocks   
Name: Carlos
Date: 2008-05-27 4:28:18 AM
Comment:
I think these confusing terms between STUBS and MOCKS.
You've created a mock, for help to test the class, this is a stub not a mock. I recommend you read this article.

http://martinfowler.com/articles/mocksArentStubs.html
Title: Great Tutorial   
Name: Steve Smith
Date: 2008-03-22 12:55:29 PM
Comment:
It didn't click for me until I read this - been trying to learn Rhino Mocks off and on for the last week. Nice job!
Title: Thanks for sharing   
Name: Jeena
Date: 2008-01-25 9:32:33 AM
Comment:
Very good article. Thanks a lot
Title: Good introduction to Rhino Mocks   
Name: Tod Birdsall
Date: 2007-12-27 5:55:43 PM
Comment:
Thanks for the nice introduction. It was very clear and easy to follow.
Title: .   
Name: Pawel Tarnik
Date: 2007-10-10 8:39:38 AM
Comment:
Nice article, I look forward to reading the next part.
Thanks.
Title: Beginning to Mock with Rhino Mocks and MbUnit - Part 1   
Name: Lee
Date: 2007-10-09 7:46:47 PM
Comment:
Thanks for the article - it's clear and easy to follow.

Product Spotlight
Product Spotlight 





Community Advice: ASP | SQL | XML | Regular Expressions | Windows


©Copyright 1998-2024 ASPAlliance.com  |  Page Processed at 2024-04-19 5:08:19 PM  AspAlliance Recent Articles RSS Feed
About ASPAlliance | Newsgroups | Advertise | Authors | Email Lists | Feedback | Link To Us | Privacy | Search