【问题标题】:How can I apply the same unit test to different functions如何将相同的单元测试应用于不同的功能
【发布时间】:2019-11-21 20:32:47
【问题描述】:

我正在编写一个名为 Fibonacci 的类,其中包含三个静态方法,它们使用不同的方法(递归、记忆等)实现了 Fibonacci 系列的三种不同实现。

然后我创建了一个测试包,并在其中创建了一个简单的 junit 测试,用于检查将负数传递给斐波那契函数时是否引发异常:

    @Test
void testIllegalArgumentException() {
    Assertions.assertThrows(IllegalArgumentException.class,
            () -> Fibonacci.fibonacci_recursive(-2));
}

我的问题是:是否可以编写一个将函数作为参数的单个测试?换句话说,我想避免写以下内容:

@Test
void testIllegalArgumentException() {
    Assertions.assertThrows(IllegalArgumentException.class,
            () -> Fibonacci.fibonacci_recursive(-2));
}
@Test
void testIllegalArgumentException() {
    Assertions.assertThrows(IllegalArgumentException.class,
            () -> Fibonacci.fibonacci_second(-2));
}
@Test
void testIllegalArgumentException() {
    Assertions.assertThrows(IllegalArgumentException.class,
            () -> Fibonacci.fibonacci_third(-2));
}

【问题讨论】:

  • 为什么?您有三种正在测试的方法。那么为什么不进行三个测试,那么当它们中的任何一个发生故障时,它就是干净的。问题:为什么你认为可以使用三种不同的(生产代码)方法而不是三种测试......?我发现您对相同代码的推理方式不同,这很奇怪……测试只是反映了代码。那为什么不把被测代码也改一下呢……?
  • @Jocke 你是对的..但我只是为自己编码..没有代码生产不用担心 :)

标签: java unit-testing junit fibonacci


【解决方案1】:

Java 8 + Junit5 允许您创建@ParameterizedTest。作为参数列表,您可以传递要测试的函数。以下测试将使用不同的输入函数运行 3 次。

测试样本:

    @ParameterizedTest
    @MethodSource("getSource")
    void whenNegativeValue_thenThrowException(Function<Integer, Integer> function, Integer value) {
        Assertions.assertThrows(IllegalArgumentException.class,
                () -> function.apply(value));
    }

    private static Stream<Arguments> getSource() {
        Function<Integer, Integer> first = Fib::first;
        Function<Integer, Integer> second = Fib::second;
        Function<Integer, Integer> third = Fib::third;
        return Stream.of(
                Arguments.of(first, -1),
                Arguments.of(second, -2),
                Arguments.of(third, -3)
        );
    }

类实现:

public class Fib {

    public static int first(int i) {
        System.out.println("first");
        validate(i);
        return i;
    }

    public static int second(int i) {
        System.out.println("second");
        validate(i);
        return i;
    }

    public static int third(int i) {
        System.out.println("third");
        validate(i);
        return i;
    }

    private static void validate(int i) {
        if (i < 0) {
            throw new IllegalArgumentException();
        }
    }

}

【讨论】:

    【解决方案2】:

    一种基本的方法是将通用代码移到一个助手中,该助手接受要调用的函数,然后简单地从测试中调用它。

    // Helper
    public void testFibo(Supplier<Integer> supplier) {
        Assertions.assertThrows(IllegalArgumentException.class,
            supplier.get());
    }
    
    // Usage inside test
    testFibo(() -> Fibonacci.fibonacci_recursive(-2));
    

    也就是说,测试框架可以为此提供更优雅的方法;我只是不确定junit是其中之一。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-05-29
      • 1970-01-01
      • 2022-01-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多