Reputation: 3166
How can I create a test class where I can inject the class to be used for testing?
For example, let's say I have a interface ISort
and some concrete classes InsertionSort
, MergeSort
, etc which implement ISort
. Since the test cases for all ISort
are the same, How can I write a common test class and inject the concrete class to be tested?
This is what I have tried so far
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
public class SortTest {
private ISort sortingAlgorithm;
public SortTest(ISort sortingAlgorithm) {
this.sortingAlgorithm = sortingAlgorithm;
}
@Test
public void test1() {
int[] data = new int[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int[] expected = new int[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
assertArrayEquals(expected, sortingAlgorithm.sort(data));
}
@Test
public void test2() {
int[] data = new int[] {10, 9, 8, 7, 6, 5, 4, 3, 2, 1};
int[] expected = new int[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
assertArrayEquals(expected, sortingAlgorithm.sort(data));
}
// .. more tests
}
How to run tests from SortTest
using InsertionSortTest
class ?
class InsertionSortTest {
// ??
}
Upvotes: 2
Views: 164
Reputation: 822
Could be done using @Parameterized
. You will probably more documentation, just a head start, also using a factory:
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@RunWith(Parameterized.class)
public class MyTest {
private static interface SortFactory {
ISort get();
}
private String someOtherParam; // example for more data
private SortFactory sortFactory;
public MyTest(SortFactory factory, String someOtherParam) {
this.sortFactory = factory;
this.someOtherParam = someOtherParam;
}
@Parameterized.Parameters(name = "{1}") // string to show in output to identify tests, here the second parameter
public static Collection<Object[]> getTestdata() {
List<Object[]> parameters = new ArrayList<Object[]>();
parameters.add(new Object[]{ new SortFactory() {
@Override
public ISort get() {
return new MergeSort();
}
}, "merge" });
parameters.add(new Object[]{ new SortFactory() {
@Override
public ISort get() {
return new InsertionSort();
}
}, "insertion" });
return parameters;
}
@Test
public void testSort() {
int[] given = new int[]{ 2, 1 };
int[] expected = new int[]{ 1, 2 };
int[] actual = sortFactory.get().sort(given);
assertArrayEquals(expected, actual);
}
}
Upvotes: 0
Reputation: 2313
Maybe something like this would do the trick.
private static Stream<ISort> sortingType() {
return Stream.of(new InsertionSort(), new MergeSort());
}
@ParameterizedTest
@MethodSource("sortingType")
public void test1(ISort sortingAlgorithm) {
int[] data = new int[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int[] expected = new int[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
assertArrayEquals(expected, sortingAlgorithm.sort(data));
}
Upvotes: 3
Reputation: 686
Have you tried Factory Pattern
? Let's create a SortFactory
public class SortFactory {
public ISort getSortingMethod(String method) {
if(method == null) {
return null;
}
if(method.equalsIgnoreCase("InsertionSort")) {
return new InsertionSort();
}
if(method.equalsIgnoreCase("MergeSort")) {
return new MergeSort();
}
return null;
}
}
and then in your test class, you can use like this
public class SortTest {
private ISort sortingAlgorithm;
private SortFactory sortFactory = new SortFactory();
@Test
public void test1() {
int[] data = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int[] expected = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
sortingAlgorithm = sortFactory.getSortingMethod("MergeSort");
assertArrayEquals(expected, sortingAlgorithm.sort(data));
}
@Test
public void test2() {
int[] data = new int[] { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 };
int[] expected = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
sortingAlgorithm = sortFactory.getSortingMethod("InsertionSort");
assertArrayEquals(expected, sortingAlgorithm.sort(data));
}
}
Upvotes: 1