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?
JUnit Jupiter @RepeatedTest annotation is used to repeat the test case for specified no. of times. Each invocation of the test case behaves like a regular @Test method, so it has support for the same lifecycle callbacks and extensions in JUnit 5.
The platform changes in a highly incompatible way and the Vintage engine will no longer be supported. This is not to be expected in the near future.
To use the JUnit rules, we need to add the @Rule annotation in the test. @Rule: It annotates the fields. It refer to the rules or methods that returns a rule. The annotated fields must be public, non-static, and subtypes of the TestRule or MethodRule.
Explanation: The default JUnit package is “org,junit”.
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.
I use #2 approach for JUnit and TestNG test cases. This is most convenient and easy to maintain. Its also straight forward to pick up (since its native to OOD to have base class that has common methods). To me unit test classes are no different than regular project classes...so I do apply similar design considerations.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With