JUnit5常用注解的使用


Posted in Java/Android onJuly 02, 2021
目录
  • 20个注解
  • 元注解和组合注解
  • 小结
  • 参考资料:

注解(Annotations)是JUnit的标志性技术,本文就来对它的20个注解,以及元注解和组合注解进行学习。

20个注解

在org.junit.jupiter.api包中定义了这些注解,它们分别是:

@Test 测试方法,可以直接运行。

@ParameterizedTest 参数化测试,比如:

@ParameterizedTest
@ValueSource(strings = { "racecar", "radar", "able was I ere I saw elba" })
void palindromes(String candidate) {
    assertTrue(StringUtils.isPalindrome(candidate));
}

@RepeatedTest 重复测试,比如:

@RepeatedTest(10)
void repeatedTest() {
    // ...
}

@TestFactory 测试工厂,专门生成测试方法,比如:

import org.junit.jupiter.api.DynamicTest;

@TestFactory
Collection<DynamicTest> dynamicTestsFromCollection() {
    return Arrays.asList(
        dynamicTest("1st dynamic test", () -> assertTrue(isPalindrome("madam"))),
        dynamicTest("2nd dynamic test", () -> assertEquals(4, calculator.multiply(2, 2)))
    );
}

@TestTemplate 测试模板,比如:

final List<String> fruits = Arrays.asList("apple", "banana", "lemon");

@TestTemplate
@ExtendWith(MyTestTemplateInvocationContextProvider.class)
void testTemplate(String fruit) {
    assertTrue(fruits.contains(fruit));
}

public class MyTestTemplateInvocationContextProvider
        implements TestTemplateInvocationContextProvider {

    @Override
    public boolean supportsTestTemplate(ExtensionContext context) {
        return true;
    }

    @Override
    public Stream<TestTemplateInvocationContext> provideTestTemplateInvocationContexts(
            ExtensionContext context) {

        return Stream.of(invocationContext("apple"), invocationContext("banana"));
    }
}

@TestTemplate必须注册一个TestTemplateInvocationContextProvider,它的用法跟@Test类似。

@TestMethodOrder 指定测试顺序,比如:

import org.junit.jupiter.api.MethodOrderer.OrderAnnotation;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;

@TestMethodOrder(OrderAnnotation.class)
class OrderedTestsDemo {

    @Test
    @Order(1)
    void nullValues() {
        // perform assertions against null values
    }

    @Test
    @Order(2)
    void emptyValues() {
        // perform assertions against empty values
    }

    @Test
    @Order(3)
    void validValues() {
        // perform assertions against valid values
    }

}

@TestInstance 是否生成多个测试实例,默认JUnit每个测试方法生成一个实例,使用这个注解能让每个类只生成一个实例,比如:

@TestInstance(Lifecycle.PER_CLASS)
class TestMethodDemo {

    @Test
    void test1() {
    }

    @Test
    void test2() {
    }

    @Test
    void test3() {
    }

}

@DisplayName 自定义测试名字,会体现在测试报告中,比如:

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

@DisplayName("A special test case")
class DisplayNameDemo {

    @Test
    @DisplayName("Custom test name containing spaces")
    void testWithDisplayNameContainingSpaces() {
    }

    @Test
    @DisplayName("?°□°)?")
    void testWithDisplayNameContainingSpecialCharacters() {
    }

    @Test
    @DisplayName("?")
    void testWithDisplayNameContainingEmoji() {
    }

}

@DisplayNameGeneration 测试名字统一处理,比如:

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.DisplayNameGeneration;
import org.junit.jupiter.api.DisplayNameGenerator;
import org.junit.jupiter.api.IndicativeSentencesGeneration;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;

class DisplayNameGeneratorDemo {

    @Nested
    @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class)
    class A_year_is_not_supported {

        @Test
        void if_it_is_zero() {
        }

        @DisplayName("A negative value for year is not supported by the leap year computation.")
        @ParameterizedTest(name = "For example, year {0} is not supported.")
        @ValueSource(ints = { -1, -4 })
        void if_it_is_negative(int year) {
        }

    }

    @Nested
    @IndicativeSentencesGeneration(separator = " -> ", generator = DisplayNameGenerator.ReplaceUnderscores.class)
    class A_year_is_a_leap_year {

        @Test
        void if_it_is_divisible_by_4_but_not_by_100() {
        }

        @ParameterizedTest(name = "Year {0} is a leap year.")
        @ValueSource(ints = { 2016, 2020, 2048 })
        void if_it_is_one_of_the_following_years(int year) {
        }

    }

}

@BeforeEach 在每个@Test, @RepeatedTest, @ParameterizedTest, or @TestFactory之前执行。

@AfterEach 在每个@Test, @RepeatedTest, @ParameterizedTest, or @TestFactory之后执行。

@BeforeAll 在所有的@Test, @RepeatedTest, @ParameterizedTest, and @TestFactory之前执行。

@AfterAll 在所有的@Test, @RepeatedTest, @ParameterizedTest, and @TestFactory之后执行。

@Nested 嵌套测试,一个类套一个类,例子参考上面那个。

@Tag 打标签,相当于分组,比如:

import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;

@Tag("fast")
@Tag("model")
class TaggingDemo {

    @Test
    @Tag("taxes")
    void testingTaxCalculation() {
    }

}

@Disabled 禁用测试,比如:

import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;

@Disabled("Disabled until bug #99 has been fixed")
class DisabledClassDemo {

    @Test
    void testWillBeSkipped() {
    }

}
@Timeout 对于test, test factory, test template, or lifecycle method,如果超时了就认为失败了,比如:

class TimeoutDemo {

    @BeforeEach
    @Timeout(5)
    void setUp() {
        // fails if execution time exceeds 5 seconds
    }

    @Test
    @Timeout(value = 100, unit = TimeUnit.MILLISECONDS)
    void failsIfExecutionTimeExceeds100Milliseconds() {
        // fails if execution time exceeds 100 milliseconds
    }

}

@ExtendWith 注册扩展,比如:

@ExtendWith(RandomParametersExtension.class)
@Test
void test(@Random int i) {
    // ...
}

JUnit5提供了标准的扩展机制来允许开发人员对JUnit5的功能进行增强。JUnit5提供了很多的标准扩展接口,第三方可以直接实现这些接口来提供自定义的行为。

@RegisterExtension 通过字段注册扩展,比如:

class WebServerDemo {

    @RegisterExtension
    static WebServerExtension server = WebServerExtension.builder()
        .enableSecurity(false)
        .build();

    @Test
    void getProductList() {
        WebClient webClient = new WebClient();
        String serverUrl = server.getServerUrl();
        // Use WebClient to connect to web server using serverUrl and verify response
        assertEquals(200, webClient.get(serverUrl + "/products").getResponseStatus());
    }

}

@TempDir 临时目录,比如:

@Test
void writeItemsToFile(@TempDir Path tempDir) throws IOException {
    Path file = tempDir.resolve("test.txt");

    new ListWriter(file).write("a", "b", "c");

    assertEquals(singletonList("a,b,c"), Files.readAllLines(file));
}

元注解和组合注解

JUnit Jupiter支持元注解,能实现自定义注解,比如自定义@Fast注解:

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import org.junit.jupiter.api.Tag;

@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Tag("fast")
public @interface Fast {
}

使用:

@Fast
@Test
void myFastTest() {
    // ...
}

这个@Fast注解也是组合注解,甚至可以更进一步和@Test组合:

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Tag("fast")
@Test
public @interface FastTest {
}

只用@FastTest就可以了:

@FastTest
void myFastTest() {
    // ...
}

小结

本文对JUnit20个主要的注解进行了介绍和示例演示,JUnit Jupiter支持元注解,可以自定义注解,也可以把多个注解组合起来。

参考资料:

https://junit.org/junit5/docs/current/user-guide/#writing-tests-annotations

https://vitzhou.gitbooks.io/junit5/content/junit/extension_model.html#概述

到此这篇关于JUnit5常用注解的使用的文章就介绍到这了,更多相关JUnit5注解内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Java/Android 相关文章推荐
Java Shutdown Hook场景使用及源码分析
Jun 15 Java/Android
深入理解以DEBUG方式线程的底层运行原理
Jun 21 Java/Android
Java并发编程之详解CyclicBarrier线程同步
Jun 23 Java/Android
Springboot使用Spring Data JPA实现数据库操作
Jun 30 Java/Android
Java基础-封装和继承
Jul 02 Java/Android
详解JAVA的控制语句
Nov 11 Java/Android
SpringBoot中使用Redis作为全局锁示例过程
Mar 24 Java/Android
Java 关于String字符串原理上的问题
Apr 07 Java/Android
mybatis-plus模糊查询指定字段
Apr 28 Java/Android
Android存储中最基本的文件存储方式
Apr 30 Java/Android
利用正则表达式匹配浮点型数据
May 30 Java/Android
Android中View.post和Handler.post的关系
Jun 05 Java/Android
解决Swagger2返回map复杂结构不能解析的问题
SpringBoot工程下使用OpenFeign的坑及解决
Jul 02 #Java/Android
SpringBoot读取Resource下文件的4种方法
Jul 02 #Java/Android
Java基础-封装和继承
Java 泛型详解(超详细的java泛型方法解析)
SpringBoot集成Druid连接池连接MySQL8.0.11
Java使用httpRequest+Jsoup爬取红蓝球号码
You might like
先进的自动咖啡技术,真的可以取代咖啡师吗?
2021/03/06 冲泡冲煮
discuz7 phpMysql操作类
2009/06/21 PHP
PHP安全性漫谈
2012/06/28 PHP
PHP容易忘记的知识点分享
2013/04/30 PHP
php setcookie(name, value, expires, path, domain, secure) 参数详解
2013/06/28 PHP
php字符串过滤与替换小结
2015/01/26 PHP
PHP中的Trait 特性及作用
2016/04/03 PHP
jquery 选取方法都有哪些
2014/05/18 Javascript
vue.js通过自定义指令实现数据拉取更新的实现方法
2016/10/18 Javascript
微信小程序 限制1M的瘦身技巧与方法详解
2017/01/06 Javascript
layui导航栏实现代码
2017/05/19 Javascript
12条写出高质量JS代码的方法
2018/01/07 Javascript
Angular搜索场景中使用rxjs的操作符处理思路
2018/05/30 Javascript
Vue中JS动画与Velocity.js的结合使用
2019/02/13 Javascript
深入理解javascript中的this
2021/02/08 Javascript
[01:01:52]完美世界DOTA2联赛PWL S2 GXR vs Magma 第二场 11.25
2020/11/26 DOTA
树莓派中python获取GY-85九轴模块信息示例
2013/12/05 Python
Python中的index()方法使用教程
2015/05/18 Python
举例讲解Python中的迭代器、生成器与列表解析用法
2016/03/20 Python
ubuntu系统下 python链接mysql数据库的方法
2017/01/09 Python
Python字符串和字典相关操作的实例详解
2017/09/23 Python
python 解决print数组/矩阵无法完整输出的问题
2020/02/19 Python
浅谈spring boot 集成 log4j 解决与logback冲突的问题
2020/02/20 Python
解决pytorch 的state_dict()拷贝问题
2021/03/03 Python
CSS书写规范、顺序和命名规则
2014/03/06 HTML / CSS
canvas小画板之平滑曲线的实现
2020/08/12 HTML / CSS
Emporio Armani腕表天猫官方旗舰店:乔治·阿玛尼为年轻人设计的副线品牌
2017/07/02 全球购物
马来西亚在线健康商店:Medipal Malaysia
2020/04/13 全球购物
私人会所最新创业计划书范文
2014/03/24 职场文书
乡镇三项教育实施方案
2014/03/30 职场文书
预备党员综合考察材料
2014/05/31 职场文书
一般基层干部群众路线教育实践活动个人对照检查材料
2014/11/04 职场文书
2014年计生工作总结
2014/11/21 职场文书
2016年小学教师师德承诺书
2016/03/25 职场文书
Python中的datetime包与time包包和模块详情
2022/02/28 Python
win10系统xps文件怎么打开?win10打开xps文件的两种操作方法
2022/07/23 数码科技