This is an AMP version of the article, its original content can be found here.
A Few Thoughts on Unit Test Scaffolding
When I start to repeat myself in unit test methods by creating
the same objects and preparing the data to run the test,
I feel disappointed in my design. Long test methods with a lot of code
duplication just don't look right. To simplify and shorten them,
there are basically two options, at least in Java: 1) private properties
@BeforeClass, and 2) private static
methods. They both look anti-OOP to me, and I think there is an
alternative. Let me explain.
JUnit officially suggests a test fixture:
I think it's obvious what this test is doing. First, in
it creates a "test fixture" of type
Folder. That is used in all three
tests as an argument for the
Metrics constructor. The real class being
tested here is
this.folder is something we need
in order to test it.
What's wrong with this test? There is one serious issue:
coupling between test methods. Test methods (and all tests in general)
must be perfectly isolated from each other. This means that changing
one test must not affect any others. In this example, that is not the case.
When I want to change the
countsWords() test, I have to change the internals
before(), which will affect the other method in the test "class."
With all due respect to JUnit, the idea of creating test fixtures in
@After is wrong, mostly because it encourages
developers to couple test methods.
Here is how we can improve our test and isolate test methods:
Does it look better now? We're not there yet, but now our test
methods are perfectly isolated. If I want to change one of them,
I'm not going to affect the others because I pass all configuration
parameters to a private static utility (!) method
A utility method, huh? Yes, it smells.
The main issue with this design, even though it is way better than
the previous one, is that it doesn't prevent code duplication between
test "classes." If I need a similar test fixture of type
another test case, I will have to move this static method there. Or
even worse, I will have to create a utility class.
Yes, there is nothing worse
in object-oriented programming than utility classes.
A much better design would be to use
instead of private static utilities. Here is how. First, we create a fake class
and place it into
src/main/java. This class can be used in tests
and also in production code, if necessary (
Fk for "fake"):
Here is how our test will look now:
What do you think? Isn't it better than what JUnit offers? Isn't it more reusable and extensible than utility methods?
To summarize, I believe scaffolding in unit testing must be done through fake objects that are shipped together with production code.