I have an interface List
whose implementations include Singly Linked List, Doubly, Circular etc. The unit tests I wrote for Singly should do good for most of Doubly as well as Circular and any other new implementation of the interface. So instead of repeating the unit tests for every implementation, does JUnit offer something inbuilt which would let me have one JUnit test and run it against different implementations?
Using JUnit parameterized tests I can supply different implementations like Singly, doubly, circular etc but for each implementation the same object is used to execute all the tests in the class.
I know this is old, but I learned to do this in a slightly different variation which works nicely wherein you can apply the
@Parameter
to a field member to inject the values.It's just a little cleaner in my opinion.
Based on the anwser of @dasblinkenlight and this anwser I came up with an implementation for my use case that I'd like to share.
I use the ServiceProviderPattern (difference API and SPI) for classes that implement the interface
IImporterService
. If a new implementation of the interface is developed, only a configuration file in META-INF/services/ needs to be altered to register the implementation.The file in META-INF/services/ is named after the fully qualified class name of the service interface (
IImporterService
), e.g.This file contains a list of casses that implement
IImporterService
, e.g.The factory class
ImporterFactory
provides clients with concrete implementations of the interface.The
ImporterFactory
returns a list of all implementations of the interface, registered via the ServiceProviderPattern. ThesetUp()
method ensures that a new instance is used for each test case.The
ImporterFactory.INSTANCE.getImplementations()
method looks like the following:Expanding on the first answer, the Parameter aspects of JUnit4 work very well. Here is the actual code I used in a project testing filters. The class is created using a factory function (
getPluginIO
) and the functiongetPluginsNamed
gets all PluginInfo classes with the name using SezPoz and annotations to allow for new classes to be automatically detected.Note it is important (I personally have no idea why it works this way) to have the collection as a collection of arrays of the actual parameter fed to the constructor, in this case a class called PluginInfo. The wrapCollection static function performs this task.
With JUnit 4.0+ you can use parameterized tests:
@RunWith(value = Parameterized.class)
annotation to your test fixturepublic static
method returningCollection
, annotate it with@Parameters
, and putSinglyLinkedList.class
,DoublyLinkedList.class
,CircularList.class
, etc. into that collectionClass
:public MyListTest(Class cl)
, and store theClass
in an instance variablelistClass
setUp
method or@Before
, useList testList = (List)listClass.newInstance();
With the above setup in place, the parameterized runner will make a new instance of your test fixture
MyListTest
for each subclass that you provide in the@Parameters
method, letting you exercise the same test logic for every subclass that you need to test.You could actually create a helper method in your test class that sets up your test
List
to be an instance of one of your implementations dependent on an argument. In combination with this you should be able to get the behaviour you want.I'd probably avoid JUnit's parameterized tests (which IMHO are pretty clumsily implemented), and just make an abstract
List
test class which could be inherited by tests implementations:The different implementations then get their own concrete classes:
The nice thing about doing it this way (instead of making one test class which tests all implementations) is that if there are some specific corner cases you'd like to test with one implementation, you can just add more tests to the specific test subclass.