Getting started with Java Mock Objects using EasyMock

If you are familiar with unit testing and test driven development then you are most probably aware of Mock Objects.

The EasyMock website states that:

A Mock Object is a test-oriented replacement for a collaborator. It is configured to simulate the object that it replaces in a simple way. In contrast to a stub, a Mock Object also verifies whether it is used as expected.
Mock Objects were introduced at XP 2000 by Tim Mackinnon, Steve Freeman and Philip Craig with the Endo-Testing: Unit Testing with Mock Objects paper.

So how do you use them? Basically you want to test some code that depends on a number of other objects. Some of these objects might have unwanted side effects like talking to a database, or accessing an external URL.

Rather than passing in the real implementation (with the above side effects) you would pass in a mock or stub instead. The mock can be pre-wired to expect a number of calls to it's methods from the code under test and will record these calls for verification later. Typically these mock objects were written by hand and so have fairly simple implementations, EasyMock removes that hard work by using Java's proxy mechanism to do most of the heavy lifting for you.

EasyMock has four stages:
  1. createMock - Create the mock based on an existing interface or class
  2. expect - Record the method calls that you expect your code under test to call indicating what you expect to be returned, if valid
  3. replay - Set the mock into 'playback' mode which switches the mock into 'real' mode and starts recording method calls and returning objects as set up in the previous stage
  4. verify - make sure that the right methods were called in the right order
Note: The standard download of EasyMock out of the box only supports creating mocks based on interfaces, if you also want to make mocks based on classes then you also need to download EasyMock Class Extensions. Then you don't use:
import static org.easymock.EasyMock.*;
you use this instead:
import static org.easymock.classextension.EasyMock.*;
And now for an example...

Let's assume we are developing a reporting object which manipulates the output of a database query. It's going to parse through a JDBC ResultSet object and do something with the results. We want the parse() method to return false if there are no rows within the ResultSet:
class ResultReporter {

boolean parse(ResultSet results) throws SQLException {
if (!results.next()) {
return false;
}

// do something with the results

return true;
}
}
So how do we test this method? We could run an SQL query against a database and then pass the ResultSet in but that would be slow and rely on external resources. We could handcode a mock version - but have you seen how many methods the ResultSet interface has?!? Or we could use EasyMock to help us out:
public class ResultReporterTest {

@Test
public void parseReturnsFalseIfPassedAnEmptyResultSet() throws SQLException {

ResultSet mockResultSet = createMock(ResultSet.class); // 1

expect(mockResultSet.next()).andReturn(false); // 2

replay(mockResultSet); // 3

ResultReporter reporter = new ResultReporter();
assertFalse(reporter.parse(mockResultSet));

verify(mockResultSet); // 4
}
}

Technorati Tags: , , , , , , , , ,

4 comments:

Richard said...

Thanks for this Andy. That's a pretty impressive reporting tool you are working on! How about a more complicated scenario? Is the order of calling the expect(...) methods verified by the call to verify() at the end?

Andy Kayley said...

nice one about the classextension. That has caused me a little pain only being able to do this with interfaces before.

Chandrakala said...

Thanks Andy, Description on EasyMock is helpful!

Iranna said...

Thanks Andy, This helped me a lot!