2

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 {
    // ??
}
cyberpirate92
  • 3,076
  • 4
  • 28
  • 46
  • On same lines of https://stackoverflow.com/questions/42884466/how-to-test-a-controller-with-constructor-injection-by-mockmvc – Raghuveer Dec 10 '19 at 07:58
  • @Raghuveer The question you linked is related to Spring components, I'm not sure how it can be applied in my case – cyberpirate92 Dec 10 '19 at 08:27

3 Answers3

3

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));
}
Morvader
  • 2,317
  • 3
  • 31
  • 44
1

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));
}
}
Tuan Hoang
  • 586
  • 1
  • 7
  • 14
0

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);
    }

}
sotix
  • 822
  • 1
  • 8
  • 23