I have an interface, e.g.:
public interface Thing {
FrobResult frob(FrobInput);
}
And several implementations of that interface (e.g. NormalThing
, ImmutableThing
, AsyncThing
) that I am trying to test.
Many of my test methods are really about ensuring that the interface is implemented correctly, and thus are duplicated across each Thing
implementation. In JUnit 3 a common solution to this would be to create a base class (extending TestCase
) that is then subclassed by each implementation class. But is this the correct approach for JUnit 4?
Possible alternatives in (I believe) ascending order of preference:
Cut'n'paste the duplicated test methods. Not DRY at all, but I guess less worrisome in tests than it would be in production code.
Create an abstract class with @Test
methods, and subclass it for each implementation test class. (Commonly seen with JUnit 3 tests -- is this still a good way to go in JUnit 4?)
Put the common test methods into a helper class, and invoke it on each implementation. (Composition instead of inheritance.)
What's the best practice for doing #3? Maybe a @RunWith(Parameterized.class)
test that is parameterized with each implementation? Or is there a better way to accomplish this?
Yes, it is the correct approach to create a base class that is then subclassed by each implementation class in JUnit4, too.
I prefer the base test class for the interface to be abstract, i.e. your "alternative" 2, since I have made good experience in mimicing the inheritance hierarchy from the production code for the test code. So if you have interface I
and implementations S1
, S2
and S3
, you make the abstract test class TestI
and the test classes TestS1
, TestS2
and TestS3
.
Test cases should be speaking, i.e. tell a story. By choosing -- as always -- method names carefully and use clean behavioral subtyping only, inheritance does not obfuscate this.