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 initialized through
@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
prepare(), 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 of
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
Folder in 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 "fake" objects 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.