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
@Testmethods, 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
Iand implementationsS1,S2andS3, you make the abstract test classTestIand the test classesTestS1,TestS2andTestS3.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.