6.1 Introduction

Writing tests for
simple, standalone Java classes is easy. Just create an instance of
your class and run tests against its methods. But testing gets a
whole lot more interesting for classes with complex dependencies on
other parts of your application. When testing becomes difficult,
consider refactoring your code in order to minimize dependencies. But
there will always be cases where classes cannot be tested in
isolation.

Suppose that a class named Automobile only runs in
the context of a class named Engine. In order to
test all aspects of the Automobile class, you find
that you have to create many different kinds of
Engines. Rather than create real
Engine objects, which may require a lot of setup
logic, you can write a dummy Engine
implementation. This dummy implementation is known as a mock object
and it provides a simple way to set up fake testing data.

The mock Engine can even include assertions to
ensure that instances of Automobile use the
Engine correctly. For example, the
Engine may verify that
Automobile only calls the Engine.startup(
) method one time. This ability to verify that objects use
their environment correctly is a key advantage of mock objects when
compared to other testing techniques that only check to see if
classes react to method calls correctly.

A mock object is a "fake"
implementation of a class or interface, almost always written for the
specific purpose of supporting unit tests. When writing JDBC unit
tests, you might create mock implementations of interfaces such as
Connection, ResultSet, and
Statement. In the case of Swing code, you might
create a mock implementation of the
TableModelListener interface. You create mock
objects that always return well-known data and your unit tests use
these to exercise your application logic without relying on real
objects or databases.

Mock objects should be simple, and should not have
dependencies on other mock objects or too
many other parts of your application. If your mock objects require a
lot of complex setup before they are useful, you probably made them
too complex and should look for ways to refactor your code.
Additionally, mock objects can provide a
self-validation mechanism whereby you can set
up an expected set of conditions. As soon as an expectation is
violated, the mock object fails the current test. Self-validation
helps you locate problems as soon as they occur. If you reuse the
same mock object in many different tests, this ability to perform
some types of self-validation ensures that you do not have to
duplicate the same validation logic in all of your tests.

The recipes in this chapter show a few different ways to implement
and use the concept of mock objects. In the simplest form, a mock
object is a dummy implementation of a Java interface. You implement
specific methods that only return data pertinent to your unit tests.
We also show how to use Mock Objects, an open source project
containing mock implementations of many well-known Java interfaces
and abstract classes. Finally, we introduce MockMaker, another open
source tool for automatically generating new mock objects.

What Is a Mock Object?

There are two widely accepted interpretations of the
term
mock object:

The generic definition states that a mock object is any
dummy object that stands in for a real
object that is not available, or is difficult to use in a test case.

A more rigid interpretation states that a mock object must have the
ability to set up expectations and provide a self-validation
mechanism.

Recipe 6.3 shows an example of a mock object that
supports expectations and self-validation. This is also the approach
taken by tools like MockMaker when they generate mock objects for
you. We believe that this is a useful approach because it provides a
standard, well-understood way to support these features.

On the other hand, if your tests do not require sophisticated mock
objects, there is nothing wrong with the first definition listed
above. In our opinion, you should write mock objects to support your
tests, only adding features that you currently need.