Using Mocks to Verify Interactions

[article]
Summary:

In the March 2006 issue of Better Software magazine, Dan North began a discussion of the evolution of behavior-driven development from test-driven development. Here, North continues the conversation with closer look at "mocks," utility classes that, for testing purposes, pretend to be some component or service with which your object will interact.

In my March 2006 Better Software magazine article, "Behavior Modification," I introduce behavior-driven development (BDD) as an evolution of established agile practices, including test-driven development (TDD). Using TDD, you write a test method to describe the behavior you are about to implement, next you write the code that implements the behavior, finally you run the test method to make sure everything works.

Typically the test executes some code then, using JUnit's Class assertEquals(...) family of methods, it asserts that certain fields or properties have expected values. The problem with this is that often by the time you get to assert anything, you've already missed all the action! For instance, if an object is expected to send an email or display something on a screen, after the fact it can be difficult to verify anything useful based on the state of some objects. You could set up expensive infrastructure like a mail gateway and a client inbox to verify against, but that isn't very appealing for a single test.

A mock is a utility class that attempts to address this problem. The mock pretends to be some component or service with which your object will interact. You can set it up with stubbed values in the form of canned responses to methods ("if anyone asks how much is in the account via the getAccountBalance() method, respond with $300"). You can also tell it to expect certain method calls ("someone should call the sendEmail(email) method with an email to [email protected]").

If any unexpected methods are called on a mock, it causes the test to fail. At the end of the test, the mock ensures it has been called as expected and causes a failure if any method invocations were missed.

In the article, I mentioned that I wrote a test to ensure that a ClientDetailsValidator interacted correctly with an AgeCalculator. Whenever I write a test that verifies interactions, I start with the following template:

public void shouldDoSomething() {
m// given...
m// expect...
m// when...
m// then...
}


It reads: given some initial setup, expect some interactions, when I execute some behavior, then ensure the outcome. This causes you to think about the behavior in stages. For this example, I had:

public void shouldCalculateAge() {
m// given...
m// I create a mock AgeCalculator

m// I create a ClientDetailsValidator
m// passing in the mock calculator
m// via its constructor

m// I set an age and a date of birth
m// in the validator

m// expect...
m// the "calculateAge" method to be
m// invoked with the age and date of
m// birth I set in the validator

m// when...
m// I execute the validator

m// then...
m// ensure the expected method was called
}


To be able to verify the interaction, I replaced the real AgeCalculator with a mock. In this example, the mock was set up with a single expectation (the calculateAge method should be called with particular values) and injected into the ClientDetailsValidator via its constructor. Mocks are particularly useful as you adopt the strategy of "discovering" dependencies, like I did with AgeCalculator.

But I'm not satisfied with the word "mock." It doesn't describe the clever dual role that mocks play, as both a pretend object and something that is aware that it is a pretend object. I am leaning toward the term "actor." If I have an actor for an AgeCalculator, I can either talk to it as an actor--setting up its script and such--or (quite literally) cast it into its role of AgeCalculator and have it play its part. In this context, it is like an actor from Candid Camera. The poor ClientDetailsValidator has no idea it's being duped.

Verify State When Appropriate
Some very experienced developers remain unconvinced about verifying interactions using mocks. Their position is - how an object talks to other objects is its own business and shouldn't be explicitly defined in a test method. Instead, the test should verify an object's state (or data) to ensure something happened.

I tend to use a mixture of both, and again the behavior vocabulary helps. For behavior that is best described in terms of interactions, I'll use mocks. For behavior that produces an output (say a calculation) I'll verify the result.

In general, if you look at a system as being made up of cooperating components (aka services or subsystems), then for the classes within an individual component I tend to verify interactions, and at the "edges" of a component or service--when there is some tangible effect on the outside world or a message being passed around--I will verify state.

Resources

For mocking in Java, check out EasyMock. For .Net, NMock is at www.nmock.org.

About the author

AgileConnection is a TechWell community.

Through conferences, training, consulting, and online resources, TechWell helps you develop and deliver great software every day.