简体   繁体   English

如何将相同的单元测试应用于不同的功能

[英]How can I apply the same unit test to different functions

I am writing a class called Fibonacci which contains three static methods implementing three different implementations of the Fibonacci series using different approaches (recursion, memoization, etc.).我正在编写一个名为 Fibonacci 的 class,其中包含三个 static 方法,使用不同的方法(递归、记忆等)实现了 Fibonacci 系列的三种不同实现。

Then I've created a test package and inside it a simple junit test which checks whether an exception is thrown when a negative number is passed to the fibonacci function:然后我创建了一个测试 package 并在其中创建了一个简单的 junit 测试,该测试检查将负数传递给斐波那契 ZC1C425268E68385D1AB5074C17A94F14 时是否引发异常:

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

My question is: is it possible to write one single test which takes a function as parameter?我的问题是:是否可以编写一个以 function 作为参数的测试? In other words I would like to avoid writing the following:换句话说,我想避免写以下内容:

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

Java 8 + Junit5 allows you to create @ParameterizedTest . Java 8 + Junit5 允许您创建@ParameterizedTest As list of parameters you can pass functions you want to test.作为参数列表,您可以传递要测试的函数。 Following test will run 3 times with different input functions.以下测试将使用不同的输入功能运行 3 次。

Test sample:测试样品:

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

Class implementation: Class 实现:

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

}

A basic approach would be to move the common code out to a helper that accepts the function to invoke and simply call that from the test(s).一个基本的方法是将通用代码移到一个接受 function 的帮助程序中来调用并简单地从测试中调用它。

// Helper
public void testFibo(Supplier<Integer> supplier) {
    Assertions.assertThrows(IllegalArgumentException.class,
        supplier.get());
}

// Usage inside test
testFibo(() -> Fibonacci.fibonacci_recursive(-2));

That said, testing frameworks can provide more elegant ways to this;也就是说,测试框架可以为此提供更优雅的方法; I'm just not sure junit is one of them.我只是不确定 junit 是其中之一。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM