Testing with Mock Objects

CodeGuru content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More.

Mock objects are useful when performing unit testing and can provide a best
solution in terms of testability. I will present the new NMock 2.0 (Release
Candidate 1) library and show how you can use it to implement mock objects.

Mock objects are used as abstractions for dependencies of a
class under test and are used to effectively isolate the class under test to
ensure proper test verification. For example, if Class A uses a class that is an
abstraction for a network service, I don’t want to have to go through the effort
of setting up a connection and verifying connectivity just to be able to test.
Therefore, I create a mock for the other class, and define how it should behave. I then write my tests
for Class A based on the expected behavior of the dependency. This effectively
decouples a class from its dependencies and makes the entire development and
testing process much more smooth.

A mock object is a testing pattern that
is used to test interfaces rather than specific implementations of classes. This
is done by defining the expectations of the methods of those classes, and then
verifying that your expectations were met after calling the methods. This can be
useful for classes that are not yet developed, difficult to setup for testing,
or dependent on an external resource such as a database or web service, or for
classes that perform prohibitively slowly, such that the execution time for the
unit tests using the actual implementation would be too great.

The Example Application

In the spirit of the Halloween season, I have set about to
develop an application for a pumpkin patch. The pricing of pumpkins (or any
commodity) can fluctuate greatly based on current geopolitical conditions. The
business stakeholder has asked that the system retrieves the actual price of a
pound of pumpkin as determined by current market conditions in real-time. I have
decided to implement this using a web service that queries the global pumpkin
syndicate database and returns the current price for a pound of pumpkins. The
pumpkin prices at the patch are also dictated by the number of days until
Halloween (the closer to Halloween, the more expensive a pumpkin will become).
The stakeholder would like to be able to set a markup percent for the price of
pumpkins on a daily basis. This will be a value that is stored in the database.

As it turns out, this application is an excellent candidate
for the use of mock objects. I have two external dependencies, the database
which stores the daily markup amount, and the web service that queries for the
real-time price of a pound of pumpkins. For the web service, I will create an
interface called IPumpkinPriceService with a single method that returns
the current price of pumpkins. For database interaction, I will create an
interface called IPumpkinDataManager that gets &
sets the today’s price markup percent, as well as some other basic methods.

namespacePumpkinPatch.Services
{
public interface IPumpkinPriceService
{
double GetPricePerPound();
}
}

namespace PumpkinPatch.Data
public interface IPumpkinDataManager
{
IList<Pumpkin> GetPumpkins();
int AddPumpkin(Pumpkin p);
doubleTodaysMarkupPercent
{
get;
set;
}
}
}

In the business logic layer of the application, I will create
a PumpkinPricer class that uses an instance of IPumpkinDataManager and
IPumpkinPricer service to calculate the price of a pumpkin based on its weight,
today’s markup and the market price of a pound of pumpkin,

namespace PumpkinPatch.BusinessLogic
{
public class PumpkinPricer : IPumpkinPricer
{
private IPumpkinPriceService pumpkinPriceService;
private IPumpkinDataManager pumpkinDataManager;
public PumpkinPricer(IPumpkinDataManager pumpkinDataMgrIn, IPumpkinPriceService pumpkinPriceServIn)
{
this.pumpkinDataManager = pumpkinDataMgrIn;
this.pumpkinPriceService = pumpkinPriceServIn;
}

#region IPumpkinPricer Members

public double GetPrice(Pumpkin p)
{
doublepricePerPound = this.pumpkinPriceService.GetPricePerPound();
double todaysMarkupPercent = this.pumpkinDataManager.TodaysMarkupPercent;
return (pricePerPound * p.Weight) * (1.0 + todaysMarkupPercent);
}
#endregion
}
}

Note that I have used constructor injection to provide
added flexibility and make it easier to test the PumpkinPricer class. To
learn more about dependency injection, please see my last article here.


Now, to verify that the PumpkinPricer calculates the price of
a pumpkin correctly, I will create unit tests that pass mock objects to the
constructor of the PumpkinPricer object. This ensures that my unit tests will
isolate the PumpkinPricer, and won’t be dependant on calls to the database or
calls to a remote web service. The goal of my tests is to prove that, if the
IPumpkinDataManager and the IPumpkinPriceService work as expected then the PumpkinPricer will correctly
calculate the price.

Creating the Tests with Mock Objects

In my unit tests, I am going to use mock objects to represent
the IPumpkinDataManager and IPumpkinPriceService objects in order to isolate the
PumpkinPricer from its external dependencies. With NMock 2.0, you first create
an instance of your mock object before defining its expected behavior. Since the
price of pound of pumpkins changes by the second, I want to simplify my test by
simply returning an unchanging amount each time the GetPricePerPound() method is
called.


Mockery mocks = new Mockery();
IPumpkinPriceService mockService = mocks.NewMock<IPumpkinPriceService>();
//Define the expectations of the mockService
//(the method named GetPricePerPound will return 1.49 as the price)
Expect.Once
.On(mockService)
.Method(“GetPricePerPound”)
.WithNoArguments()
.Will(Return.Value(1.49));

So, each time the GetPricePerPound() method is called on the
mockService, 1.49 will be returned. I also want to set the mockDataManager’s
TodaysMarkupPercent property to return 0.10. Properties can be set using
GetProperty.

IPumpkinDataManager mockDataManager = mocks.NewMock<IPumpkinDataManager>();
//Define the expectations of the mockDataManager
//todays markup is 10% over the normal price
Expect.Once
.On(mockDataManager)
.GetProperty(“TodaysMarkupPercent”)
.Will(Return.Value(0.10));

My expectation is that the TodaysMarkupPercent property will be invoked once and
will return the value 0.10. Now that I have defined how the mocks will behave,
it’s time to test the PumpkinPricer.

//instantiate a 5 lb pumpkin
Pumpkin p = new Pumpkin();
p.Weight = 5.00;

//instantiate the PumpkinPricer using the mocks
PumpkinPricer pricer = new PumpkinPricer(mockDataManager,
mockService);

//get the calculated price
double actualPrice = pricer.CalculatePrice(p);
//get the expected price
double expectedPrice = (5.00 * 1.49) * 1.10;
//compare actual to expected
Verify.That(actualPrice, Is.EqualTo(expectedPrice));

mocks.VerifyAllExpectationsHaveBeenMet();

To test the CalculatePrice() method of the PumpkinPricer, I
passed it the two mocks via its constructor. The mocks were used by the
CalculatePrice() method to calculate the price of the 5 pound pumpkin. Since I
setup the TodaysMarkupPercent property of the IPumpkinDataManager mock to
return 0.10 for this test, and the GetPricePerPound() method of the mockService
should return 1.49, then the expected return value of the CalculatePrice method
should be equivalent to 5 (# of lbs of the pumpkin) * 1.49 (price / lb) * (1 +
0.10 (today’s markup)). I used NMock’s Verify class to verify that the
actualPrice is equal to the expectedPrice. If this were not the case, then a
NMock.Internal.ExpectationException would be thrown. Lastly, we call the
VerifyAllExpectationsHaveBeenMet() method. This ensures
that the GetPricePerPound method and the TodaysMarkupPercent property were
actually invoked as expected during the course of the test.

Evolving the Design

Now, since requirements change frequently, I want to modify
the IPumpkinPriceService to retrieve historical pumpkin prices. Therefore, I am
going to overload the GetPricePerPound method to take a DateTime variable as a
parameter. The change to the interface is shown below. Also, since this is
making a call to an external 3rd-party web service not under my
authority, it would be realistic to pass some sort of credentials to the
3rd party. Therefore, I have added properties to the interface to
retrieve the required credentials that must be passed to the GetPricePerPound()
method.

public interface IPumpkinPriceService
{
double GetPricePerPound(string userName, string password);
double GetPricePerPound(DateTime dt, string userName, string password);
string PriceServiceUserName { get; }
string PriceServicePassword { get; }
}

Now, I update the CalculatePrice() method of the PumpkinPricer class to reflect the change to
IPumpkinPriceService.

public double CalculatePrice(Pumpkin p)
{
string userName = this.pumpkinPriceService.PriceServiceUserName;
string password = this.pumpkinPriceService.PriceServicePassword;
double pricePerPound =
this.pumpkinPriceService.GetPricePerPound(DateTime.Today,
userName, password);
double todaysMarkupPercent = this.pumpkinDataManager.TodaysMarkupPercent;
return (pricePerPound * p.Weight)
* (1.0 + todaysMarkupPercent);
}

I am also going to have to modify the expectations of the
mock IPumpkinPriceService to take the appropriate parameters for the
GetPricePerPound() method and to verify that the PriceServiceUserName and
PriceServicePassword properties are accessed during the execution of the

CalculatePrice() method. Here are the updated
expectations of the CalculatePriceTest method.

//initialize a username and password for this
test

string testUserName = “TestUserName”;
string testPassword = “TestPassword”;

//the
PriceServiceUserName should be accessed at least once

Expect.AtLeastOnce
.On(mockService)
.GetProperty(“PriceServiceUserName”)
.Will(Return.Value(testUserName));

//the
PriceServicePassword should be accessed at least once

Expect.AtLeastOnce
.On(mockService)
.GetProperty(“PriceServicePassword”)
.Will(Return.Value(testPassword));

//Define
the expectations of the mockService

//(the
method named GetPricePerPound will return 1.49 as the
price)

Expect.Once
.On(mockService)
.Method(“GetPricePerPound”)
.With(DateTime.Today, testUserName,
testPassword)

.Will(Return.Value(1.49));

Note that I passed parameters to the GetPricePerPound method
using the With
statement.

Conclusion

In the above example mock objects were created to act as
stand-ins for actual implementations in order to isolate the unit under test (in
this case, the PumpkinPricer class). This makes it easier to detect defects
during development. You can find out more information about NMock by viewing this tutorial and this cheatsheet.

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read