How to generate multiple test method from JSON?

Marie_Jane98 :

I have a huge JSON-File which contains testcases. (No I don't wanna show it here because it doesn't matter in this case to know the file) I parse the json file to my junit test - that works fine. But I've got 50 testcases and if I want to show each in Junit like: "test 0 from 50 passed" and have a list like: test 1 passed, test 2 passed, test 3 failed..

I have to put each testcase into a method. How can I dynamically do this? Is this possible in Junit? Because when I'm parsing the json, I don't know how many cases I have.

Mensur Qulami :

JUnit has direct support for CSV files, which means you can import and use them easily using @CSVFileSource.

However, since your case does not involve CSV files, I tried to create parametrized tests in JUnit 5 using JSON files.

Our class under test.

public class MathClass {
    public static int add(int a, int b) {
        return a + b;
    }
}

Here's the JSON file I am using.

[
  {
    "name": "add positive numbers",
    "cases": [[1, 1, 2],[2, 2, 4]]
  },
  {
    "name": "add negative numbers",
    "cases": [[-1, -1, -2 ], [-10, -10, -20 ]]
  }
]

So, in JUnit 5 there is an annotation called @MethodSource which gives you the opportunity to provide arguments to your parametrized test. You only need to provide the method name. Here's my argument provider method.

    @SneakyThrows
    private static Stream<TestCase> getAddCases() {
        final ObjectMapper mapper = new ObjectMapper();
        TypeReference<List<Case>> typeRef = new TypeReference<>() {};
        final File file = new File("src/test/resources/add-cases.json");
        final List<Case> cases = mapper.readValue(file, typeRef);
        return cases.stream()
                .flatMap(caze -> caze.getCases()
                                        .stream()
                                        .map(el -> new TestCase(caze.getName(), el)));
    }

In the code above, the class Case is used to map from the json object to Java Object and since the "cases" field is a multidimensional array, to represent each test case there is a class called TestCase. (Overall, this is not important for you, since you already are able to parse it, but I wanted to put it here anyway).

Finally, the test method itself.

    @ParameterizedTest(name = "{index} : {arguments}")
    @MethodSource("getAddCases")
    void add_test(TestCase testCase) {
        final List<Integer> values = testCase.getValues();
        int i1 = values.get(0);
        int i2 = values.get(1);
        int e = values.get(2);
        assertEquals(e, MathClass.add(i1, i2));
    }

@ParametrizedTest annotation takes a name argument where you can provide a template for the test names. I just played around with the toString method of TestCase class to achieve a better description for each test case.

@Override
public String toString() {
    return String.format("%s : (%s, %s) ==> %s", name, values.get(0), values.get(1), values.get(2));
}

And voila!

Test cases

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=238775&siteId=1