junit5

junit5

起男 848 2020-07-10

junit5

注解

注解描述
@Test表示方法是测试方法。与junit4的@Test注解不同的是,这个注解没有任何属性,因为junit jupiter中的测试扩展是基于它们自己的专用注解来操作的
@ParameterizedTest表示方法是参数化测试
@RepeatedTest表示方法是用于重复测试的测试模板
@TestFactory表示方法是用于动态测试的测试工厂
@TestTemplate表示方法是测试用例的模板
@TestInstance用于为被注解的测试类配置测试实例生命周期
@DisplayName声明测试类或测试方法的自定义显示名称
@BeforeEach表示被注解的方法应在每个测试方法之前执行,类似于junit4@Before
@AfterEach表示被注解的方法应在每个测试方法之后执行,类似于junit4@After
@BeforeAll表示被注解的方法应在所有测试方法之前执行,类似于junit4@BeforeClass
@AfterEach表示被注解的方法应在所有测试方法之前执行,类似于junit4@AfterClass
@Nested表示被注解的类是一个嵌套的非静态测试类
@Tag在类或方法级别声明标签,用于过滤测试
@Disabled用于禁用测试类或测试方法,类似junit4的@Ignore
@ExtendWith用于注册自定义扩展

@Test、@TestTemplate、@RepeatedTest、@BeforeAll、@AfterAll、@BeforeEach、@AfterEach注解的方法不能有返回值

显示名称

@DisplayName("测试类")
public class DisplayNameTest {

    @Test
    @DisplayName("测试方法一")
    void test01(){
    }

    @Test
    @DisplayName("测试方法二")
    void test02(){
    }
}
  • 测试类和测试方法可以声明自定义显示名称
  • 可以使用空格、特殊字符、汉字、甚至emojis表情符号

禁用

禁用测试案例

@Disabled
public class DisabledTesst {

    @Test
    void test01(){
        System.out.println("test01");
    }
}

禁用测试方法

public class DisabledTesst {

    @Test
    @Disabled
    void test01(){
        System.out.println("test01");
    }

    @Test
    void test02(){
        System.out.println("test02");
    }
}

不可同时在类和方法上加@Disabled注解,否则方法上的将不会生效

生命周期

  • 为了允许隔离执行单个的测试方法,并避免由于可变测试实例状态而产生的意外副作用,junit在执行每个测试方法之前创建每个测试类的新实例
  • “per-method”测试实例是junit中的默认行为
  • 如果希望在同一个测试实例上测试所有方法需要@TestInstance(TestInstance.Lifecycle.PER_CLASS)

per-class可以在非静态方法上使用@BeforeAll和@AfterAll

嵌套测试

@DisplayName("外层测试实例")
public class TestingDemo {

    @Test
    @DisplayName("外层方法")
    void test01(){
    }

    @DisplayName("内层测试实例")
    @Nested
    class WhenNew{

        @Test
        @DisplayName("内层方法")
        void test(){

        }
    }
}
  • 如果不加@Nested内层实例和内层方法将无法执行
  • 添加@Nested后可以统一执行内外层,也可以单独执行内层方法

构造函数和方法依赖注入

在之前的所有junit版本中,测试构造函数或方法都不允许有参数

  • parameterResolver定义了测试扩展的api,希望在运行时动态解析参数
  • 如果测试方法接收参数,则该参数必须在运行时有已注册的parameterResolver解析

目前有桑自动注册的内置解析器:

  • TestInfoParameterResolver:参数是TestInfo,可以用来获取当前测试有关的信息
  • RepetitionInfoParameterResolver:参数是RepetitionInfo,可以获取@RepeatedTest的重复数
  • TestReporterParameterResolver:参数是TestReporter,可以发布当前测试运行的额外数据

其他参数解析器必须通过@Extendwith 注册适当的扩展来显示启用

接口测试和默认方法

  • 允许在接口的default方法中声明测试注解
  • 如果接口或测试类用@TestInstance(TestInstance.Lifecycle.PER_CLASS)则可以在接口的default方法中声明@BeforeAll和@AfterAll

重复测试

@RepeatedTest(10)
void test01(){}
  • 使方法重复执行指定次数
  • 方法上不需要添加@Test

参数化测试

	@ParameterizedTest
    @ValueSource(strings = {"a","b"})
    void test01(String s){
        System.out.println(s);
    }
  • 使用@ParameterizedTest声明测试实方法
  • @ValueSource:可以让你指明一个原生类型的数组,并且只能每次调用一个参数
	@ParameterizedTest
    @EnumSource(TimeUnit.class)
    void test02(TimeUnit timeUnit){
        System.out.println(timeUnit);
    }
  • @EnumSource:可以指定一个枚举,每次调用一个枚举实例
	@ParameterizedTest
    @MethodSource("stringStream")
    void test03(String s){
        System.out.println(s);
    }

    static Stream<String> stringStream(){
        return Stream.of("aaa","bbb");
    }
  • @MethodSource:允许你传入一个返回stream、iterable、iterator或数组的静态工厂方法
	@ParameterizedTest
    @CsvSource({"aaa,111","bbb,222"})
    void test04(String s, Integer i){
        System.out.println(s+":"+i);
    }
  • @CsvSource:允许将参数列表以逗号分隔
	@ParameterizedTest
    @CsvFileSource(resources="/myTest.csv")
    void test05(String s, Integer i){
        System.out.println(s+":"+i);
    }
  • @CsvFileSource:可以使用classpath中的csv文件
	@ParameterizedTest
    @ArgumentsSource(MyArgumentsProvider.class)
    void test06(String s){
        System.out.println(s);
    }

    static class MyArgumentsProvider implements ArgumentsProvider{

        @Override
        public Stream<? extends Arguments> provideArguments(ExtensionContext extensionContext) throws Exception {
            return Stream.of("aaa","bbb").map(Arguments::of);
        }
    }
  • @ArgumentsSource:指向一个自定义的,可重用的ArgumentsProvider实现类