13

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:

  1. 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.

  2. 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?)

  3. 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?

Daniel Pryden
  • 59,486
  • 16
  • 97
  • 135

2 Answers2

6

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.

DaveFar
  • 7,078
  • 4
  • 50
  • 90
  • 1
    That was my first thought as well, although it feels like there ought to be some new and shiny way of doing mix-ins of test methods, since it seems like such a common case. +1 but will wait for other to chime in before giving you the checkmark. – Daniel Pryden Nov 01 '12 at 21:23
1

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.

user1697575
  • 2,830
  • 1
  • 24
  • 37
  • 1
    True that test classes need design considerations, but I wouldn't say that they are no different from regular project classes. But either way, my preference is to follow *Effective Java* Item 16: Favor composition over inheritance. Inheritance (which is really about creating an "is-a" relationship) is usually a poor way to implement code reuse. – Daniel Pryden Nov 01 '12 at 21:32
  • Well it all depends... normally I use composition & inheritance together. Some base functionality that belong only to the hierarchy I place into base class, and some functionality that can be reused outside of my hierarchy (i.e. library/component elements) I place as composition. So you should use #2 and #3 approach together (well I've added to my answer here) :) – user1697575 Nov 02 '12 at 13:43