IBM developerWorks.com has published an article by Alex Chaffee and William Pietri present a refactoring technique to create mock objects for unit tests based on the factory method design pattern.
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.
What do you think of the author's approach to mock objects?
I'm a great fan of your work and very thankful to the amount of knowledge you are disseminating via your website. I was really inspired by your rational behind ARTIMA as Learn, Think & Imagine.
Anyways....I read MockObjects article recently and I was not convinced. Matter of fact, this approach would invites lot of confusion with the real and mock objects. Very painful for larger code based projects from maintanence stand-point. Honest go Goodness....I would not recommend someone to take MockObjects path unless I've completely gone blind.
I think the approach is a little too much. They describe extracting a factory method from a creational method and overriding the factory method in the test object.
Here's their example: class Application { ... public void run() { View v = new View(); v.display(); ...
get's refactored to class Application { ... public void run() { View v = createView(); v.display(); ... protected View createView() { return new View(); } ... }
And then you test it by over-riding the factory method on your object under test: class ApplicationTest extends TestCase {
MockView mockView = new MockView();
public void testApplication { Application a = new Application() { protected View createView() { return mockView; } }; a.run(); mockView.validate(); } ...
I would go for the simpler approach.
You refactor to: class Application { ... public final void run() { View v = new View(); run( v ); ... }
protected final void run(View v) { v.display(); } ...
Then your test simply becomes: class ApplicationTest extends TestCase {
MockView mockView = new MockView();
public void testApplication { Application a = new Application(); a.run( mockView ); mockView.validate(); } ...
There are a few downsides to their approach.
1. You can't make the extracted factory method final because the test class needs to override it. Thus, you are restricting production code because of a test.
2. You are partaking in the old "override method" antipattern. A lot of OO developers go so far as suggesting that one never extend a class unless its abstract. And even then, all the non-abstract methods should be final.
3. You have to create a new factory method for every single object that the method under test wants to create. In the way that I purpose, you only really need to extract one method.