添加library,jar

@Test

它会把带有@Test的方法识别为测试方法。

assertEquals(expected, actual)

Assertion还定义了其他断言方法,例如:

· assertTrue(): 期待结果为true

· assertFalse(): 期待结果为false

· assertNotNull(): 期待结果为非null

· assertArrayEquals(): 期待结果为数组并与期望数组每个元素的值均相等

使用浮点数时,由于浮点数无法精确地进行比较

assertEquals(double expected, double actual, double delta)这个重载方法,指定一个误差值

初始化

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <version>2.2.13.RELEASE</version>
    <scope>test</scope>
</dependency>
@RunWith(SpringRunner.class)
@SpringBootTest(classes = MyStarter.class)
@WebAppConfiguration
@ComponentScan()
public class BaseTest {

    public BaseRequest buildBaseQuest(String test) {

        return request;
    }

}

Fixture

JUnit提供了编写测试前准备、测试后清理的固定代码,我们称之为Fixture。

我们要先初始化对象,我们不必在每个测试方法中都写上初始化代码,而是通过@BeforeEach来初始化,通过@AfterEach来清理资源

JUnit还提供了@BeforeAll@AfterAll,它们在运行所有@Test前后运行

因为@BeforeAll和@AfterAll在所有@Test方法运行前后仅运行一次,因此,它们只能初始化静态变量

因此,我们总结出编写Fixture的套路如下:

  1. 对于实例变量,在@BeforeEach中初始化,在@AfterEach中清理,它们在各个@Test方法中互不影响,因为是不同的实例;

  2. 对于静态变量,在@BeforeAll中初始化,在@AfterAll中清理,它们在各个@Test方法中均是唯一实例,会影响各个@Test方法。

大多数情况下,使用@BeforeEach和@AfterEach就足够了。只有某些测试资源初始化耗费时间太长,以至于我们不得不尽量“复用”时才会用到@BeforeAll和@AfterAll。

最后,注意到每次运行一个@Test方法前,JUnit首先创建一个XxxTest实例,因此,每个@Test方法内部的成员变量都是独立的,不能也无法把成员变量的状态从一个@Test方法带到另一个@Test方法。

异常测试

@Test
void testNegative() {
    assertThrows(IllegalArgumentException.class, new Executable() {
        @Override
        public void execute() throws Throwable {
            Factorial.fact(-1); // my function  throw new IllegalArgumentException();
        }
    });
}

@Test
void testNegative() {
    assertThrows(IllegalArgumentException.class, () -> {
        Factorial.fact(-1);
    });
}

条件测试

@Disabled

不让测试方法运行

为什么我们不直接注释掉@Test,而是要加一个@Disabled?这是因为注释掉@Test,JUnit就不知道这是个测试方法,而加上@Disabled,JUnit仍然识别出这是个测试方法,只是暂时不运行。它会在测试结果中显示:Tests run: 68, Failures: 2, Errors: 0, Skipped: 5

@EnabledOnOs

@DisabledOnOs(OS.WINDOWS),不在这个系统运行

@DisabledOnJre(JRE.JAVA_8):只能在Java 9或更高版本执行的测试,可以加上

@EnabledIfSystemProperty,只能在64位操作系统上执行的测试

@EnabledIfEnvironmentVariable,需要传入环境变量DEBUG=true才能执行的测试,@EnabledIfEnvironmentVariable(named = "DEBUG", matches = "true")

@Test
@EnabledOnOs(OS.WINDOWS)
void testWindows() {
    assertEquals("C:\\test.ini", config.getConfigFile("test.ini"));
}
@Test
@EnabledOnOs({ OS.LINUX, OS.MAC })
void testLinuxAndMac() {
    assertEquals("/usr/local/test.cfg", config.getConfigFile("test.cfg"));
}

参数化测试

如果待测试的输入和输出是一组数据: 可以把测试数据组织起来 用不同的测试数据调用相同的测试方法

参数化测试和普通测试稍微不同的地方在于,一个测试方法需要接收至少一个参数,然后,传入一组参数反复运行。

@ParameterizedTest

@ParameterizedTest
@ValueSource(ints = { 0, 1, 5, 100 })
// @ValueSource(ints = { -1, -5, -100 })
void testAbs(int x) {
    assertEquals(x, Math.abs(x));
}

多参数、测试结果

@MethodSource

编写一个同名的静态方法来提供测试参数, 如果静态方法和测试方法的名称不同,@MethodSource也允许指定方法名。但使用默认同名方法最方便。

@ParameterizedTest
@MethodSource
void testCapitalize(String input, String result) {
    assertEquals(result, StringUtils.capitalize(input));
}
static List<Arguments> testCapitalize() {
    return List.of( // arguments:
            Arguments.arguments("abc", "Abc"), //
            Arguments.arguments("APPLE", "Apple"), //
            Arguments.arguments("gooD", "Good"));
}

@CsvSource

它的每一个字符串表示一行,一行包含的若干参数用,分隔

@ParameterizedTest
@CsvSource({ "abc, Abc", "APPLE, Apple", "gooD, Good" })
void testCapitalize(String input, String result) {
    assertEquals(result, StringUtils.capitalize(input));
}

@CsvFileSource

我们可以把测试数据提到一个独立的CSV文件中,然后标注上@CsvFileSource

@ParameterizedTest
@CsvFileSource(resources = { "/test-capitalize.csv" })
void testCapitalizeUsingCsvFile(String input, String result) {
    assertEquals(result, StringUtils.capitalize(input));
}

JUnit只在classpath中查找指定的CSV文件,因此,test-capitalize.csv这个文件要放到test目录下

apple, Apple
HELLO, Hello
JUnit, Junit
reSource, Resource