I want to run the same JUnit tests for different interface implementations. I found a nice solution with the @Parameter option:
public class InterfaceTest{
MyInterface interface;
public InterfaceTest(MyInterface interface) {
this.interface = interface;
}
@Parameters
public static Collection<Object[]> getParameters()
{
return Arrays.asList(new Object[][] {
{ new GoodInterfaceImpl() },
{ new AnotherInterfaceImpl() }
});
}
}
This test would be run twice, first with the GoodInterfaceImpl then with the AnotherInterfaceImpl class. But the problem is I need for most of the testcases a new object. A simplified example:
@Test
public void isEmptyTest(){
assertTrue(interface.isEmpty());
}
@Test
public void insertTest(){
interface.insert(new Object());
assertFalse(interface.isEmpty());
}
If the isEmptyTest is run after the insertTest it fails.
Is there an option to run automatically each testcase with a new instance of an implementation?
BTW: Implementing a clear() or reset()-method for the interface is not really an options since I would not need it in productive code.
Just in case somebody reaches here(like I did), looking for testing multiple implementations of the same interface in .net you could see one of the approaches that I was using in one of the projects here
Below is what we are following in short
The same test project dll is run twice using vstest.console, by setting an environment variable. Inside the test, (either in the assembly initialize or test initialize) register the appropriate implementations into a IoC container, based on the environment variable value.
Create a factory interface and implementations, possibly only in your test hierarchy if you don't need such a thing in production, and make
getParameters()
return a list of factories.Then you can invoke the factory in a
@Before
annotated method to get a new instance of your actual class under test for each test method run.Here is another approach with the Template Method pattern:
The interface-oriented tests go into the base class:
For each concrete class, define a concrete test class:
A slight advantage over @Parameter is that you get the name of the concrete test class reported when a test fails, so you know right away which implementation failed.
Btw, in order for this approach to work at all, the interface must be designed in a way which allows testing by the interface methods only. This implies state-based testing -- you cannot verify mocks in the base test class. If you need to verify mocks in implementation-specific tests, these tests must go into the concrete test classes.
In Junit 5 you could do: