Mock objects are a useful way to write unit tests for objects that act as mediators. Instead of calling the real
domain objects, the tested object calls a mock domain object that
merely asserts that the correct methods were called, with the expected
parameters, in the correct order. However, when the tested object must
create the domain object, we are faced with a problem. How does the
tested object know to create a mock domain object instead of the true
domain object? In this article, software consultants Alexander Day
Chaffee and William Pietri present a refactoring technique to create
mock objects based on the factory method design pattern. < ="" ="text/">
| http://www.ibm.com/developerworks/search/searchResults.jsp?source=google&searchType=1&searchSite=dW&searchScope=dW&query=Unit+Testing+ - More dW content related to: Unit Testing | |
Unit testing has become widely accepted as a "best practice" for
software development. When you write an object, you must also provide
an automated test class containing methods that put the object through
its paces, calling its various public methods with various parameters
and making sure that the values returned are appropriate.
When you're dealing with simple data or service objects, writing
unit tests is straightforward. However, many objects rely on other
objects or layers of infrastructure. When it comes to testing these
objects, it is often expensive, impractical, or inefficient to
instantiate these collaborators.
For example, to unit test an object that uses a database, it may be
burdensome to install, configure, and seed a local copy of the
database, run your tests, then tear the local database down again. Mock
objects provide a way out of this dilemma. A mock object conforms to
the interface of the real object, but has just enough code to fool the
tested object and track its behavior. For example, a database
connection for a particular unit test might record the query while
always returning the same hardwired result. As long as the class being
tested behaves as expected, it won't notice the
difference, and the unit test can check that the proper query was
emitted.
Mock in the middle
The common coding style for testing with mock objects is to:
- Create instances of mock objects
- Set state and expectations in the mock objects
- Invoke domain code with mock objects as parameters
- Verify consistency in the mock objects
While this pattern is very effective for many cases, sometimes the
mock object cannot be passed into the object being tested. Instead,
that object is designed to either create, look up, or otherwise obtain
its collaborator.
For instance, the tested object may need to obtain a reference to an
Enterprise JavaBean (EJB) component or remote object. Or the tested
object may make use of objects with side effects that may not be
desirable in unit testing, like File objects that delete files.
Common wisdom suggests that this situation provides an opportunity
to refactor your object to make it more test-friendly. For instance,
you may change the method signature so that the collaborator object is
passed in.
In his article " http://www.ibm.com/developerworks/java/library/j-aspectj2/index.html - Test flexibly with AspectJ and mock objects ,"
Nicholas Lesiecki points out that refactoring is not always desirable,
nor does it always result in code that is cleaner or easier to
understand. In many cases, changing the method signature so the
collaborator becomes a parameter will result in a confusing, untested
snarl of code inside the method's original callers.
The heart of the problem is that the object is obtaining these
objects "on the inside." Any solution must apply to all occurrences of
this creation code. To solve this problem, Lesiecki uses a lookup
aspect or a creation aspect. In this solution, the code that performs
the lookup is replaced automatically with code that returns a mock
object instead.
Because AspectJ is not an option for some, we offer an alternative
approach in this article. Because this is, at root, a refactoring, we
will follow the presentation convention established by Martin Fowler in
his seminal book, Refactoring: Improving the Design of Existing Code (see http://www-128.ibm.com/developerworks/library/j-mocktest.html#resources - Resources ).
(Our code is based on JUnit, the most popular unit testing framework
for Java programming, though it is by no means JUnit-specific.)
|