使用@MethodSource 处理异常

Handling exceptions with @MethodSource

我刚开始在 LeetCode 上做一个名为“Two Sum”的练习,但遇到了测试问题。

现在,练习的代码如下所示:

public class TwoSumCalculator {
public int[] twoSum(int[] numbers, int target) {

    for (int i = 0; i < numbers.length; i++) {

        for (int j = i + 1; j < numbers.length; j++) {

            if (numbers[j] == target - numbers[i]) {
                return new int[]{i, j};
            }
        }
    }
    throw new IllegalArgumentException("No two sum solution");
}

}

我的测试是这样的:

class TwoSumCalculatorTest {
TwoSumCalculator twoSumCalculator = new TwoSumCalculator();

@ParameterizedTest
@MethodSource("parameters")
void findIndices(int[] expectedNumbers, int[] inputNumbers, int target) {
    int[] resultedNumbers = twoSumCalculator.twoSum(inputNumbers, target);

    assertArrayEquals(expectedNumbers, resultedNumbers);
}

private static Stream<Arguments> parameters() {
    return Stream.of(
            Arguments.of(new int[]{1, 2}, new int[]{3, 2, 4}, 6),
            Arguments.of(new int[]{0, 1}, new int[]{2, 7, 11, 15}, 9),
            Arguments.of(new int[]{0, 1}, new int[]{3, 3}, 6),
            Arguments.of(new IllegalArgumentException("No two sum solution"), new int[]{3, 1, 2}, 6));
}

}

虽然前 3 个测试通过了,但我在第 4 个参数中收到以下错误消息:

org.junit.jupiter.api.extension.ParameterResolutionException:在索引 0 处转换参数时出错:没有将类型 java.lang.IllegalArgumentException 的对象转换为类型 [I

的隐式转换

什么是更好的测试方法?

你可以做这样的事情,或者可能只是对抛出异常的情况进行单独的测试。

    @ParameterizedTest
    @MethodSource("parameters")
    void findIndices(int[] expectedNumbers, int[] inputNumbers, int target, Class expectedException) {
        if (expectedException != null) {
            assertThrows(expectedException, () -> twoSumCalculator.twoSum(inputNumbers, target));
        } else {
            int[] resultedNumbers = twoSumCalculator.twoSum(inputNumbers, target);
            assertArrayEquals(expectedNumbers, resultedNumbers);
        }
    }

    private static Stream<Arguments> parameters() {
        return Stream.of(
                Arguments.of(new int[]{1, 2}, new int[]{3, 2, 4}, 6, null),
                Arguments.of(new int[]{0, 1}, new int[]{2, 7, 11, 15}, 9, null),
                Arguments.of(new int[]{0, 1}, new int[]{3, 3}, 6, null),
                Arguments.of(null, new int[]{3, 1, 2}, 6, IllegalArgumentException.class));
    }

与其尝试在同一测试中对成功和失败案例进行参数化,我建议您分别进行测试。这使您可以使用 assertThrows 方法断言抛出的异常,并避免在测试代码中引入逻辑。

类似于:

class TwoSumCalculatorTest {
    TwoSumCalculator twoSumCalculator = new TwoSumCalculator();

    @ParameterizedTest
    @MethodSource("twoSumParameters")
    void twoSumSolutions(int[] expectedNumbers, int[] inputNumbers, int target) {
        int[] resultedNumbers = twoSumCalculator.twoSum(inputNumbers, target);

        assertArrayEquals(expectedNumbers, resultedNumbers);
    }

    @ParameterizedTest
    @MethodSource("noTwoSumParameters")
    void noTwoSumSolutions(int[] inputNumbers, int target) {
        assertThrows(IllegalArgumentException.class, () -> {
            twoSumCalculator.twoSum(inputNumbers, target);
        })
    }

    private static Stream<Arguments> twoSumParameters() {
        return Stream.of(
            Arguments.of(new int[]{1, 2}, new int[]{3, 2, 4}, 6),
            Arguments.of(new int[]{0, 1}, new int[]{2, 7, 11, 15}, 9),
            Arguments.of(new int[]{0, 1}, new int[]{3, 3}, 6)
        );

    private static Stream<Arguments> noTwoSumParameters() {
        return Stream.of(
            Arguments.of(new int[]{3, 1, 2}, 6)
            // Could add more exceptional cases here
        );
    }