Junit5 单元测试框架的使用

您所在的位置:网站首页 Junit5的@Execution注解 Junit5 单元测试框架的使用

Junit5 单元测试框架的使用

2024-06-28 18:55| 来源: 网络整理| 查看: 265

Junit5 简单使用总结

作为一款测试框架,一般我们需要从以下几个方面去考虑

TestCase : 测试用例的管理Assertions : 用例断言的管理Test Execution: 测试执行,以何种顺序执行Test Fixtures : 测试装置,测试用例运行的前后动作,用来管理测试用例的执行Test Suites: 测试套,控制用例批量运行Test Runner: 测试用例的运行器Test Result Report: 测试报告 Junit5 架构

junit5 大体由3个模块组成

Junit platform 其主要作用在JVM 上启动测试框架,支持通过命令行Gradle maven 和Api 来运行平台Junit Jupiter :核心功能 用于编写测试用例Junit vintage : 承载兼容老版本的用例运行 工程环境搭建 参考官网在pom.xml 文件中引入依赖 UTF-8 1.8 1.8 org.junit.platform junit-platform-launcher test org.junit.jupiter junit-jupiter-engine test org.junit.vintage junit-vintage-engine test org.junit junit-bom 5.8.2 pom import maven-surefire-plugin 2.22.2 用例写作之常用注解 @Test标记在方法上,表示测试用例@BeforeEach表示被注解的方法,会在每个测试用例执行之前运行,@BeforeEach 注解支持继承@AfterEach表示被注解的方法,会在每个测试用例执行之后运行,@AfterEach 注解支持继承@BeforeAll表示在所有的测试方法运行之前执行, @BeforeAll 注解可以被继承@AfterAll表示所有的测试方法运行之后执行 @BeforeAll 注解可以被继承@DisplayName声明测试类或者测试方法显示的名称,此注解不会被继承@Tag用于类或者方法上,做标签,后续可以根据标签来选择用例的执行,此注解用于类上可以被继承,用于方法上不可以被继承@Disabled用于类或者方法上 ,禁用测试类@Nested嵌套类的使用,但必须要求内部类是非静态内部类@ParameterizedTest参数化@RepeatedTest用例重复执行,可以用来测试并发场景@order指定用例的执行顺序,传入数字即可@TestMethodOrder指定用例以何种顺序执行,传入指定的MethodOrder 就可以自定义实现顺序https://junit.org/junit5/docs/current/user-guide/#writing-tests-test-execution-order-methods @DisplayName("测试计算器") @TestMethodOrder(MethodOrderer.MethodName.class) public class CalculatorTest { @BeforeAll public static void beforeAll(){ System.out.println("Calculator test Before All"); } @BeforeEach public void beforeEach(){ System.out.println("Calculator test Before Each"); } @Test @DisplayName("测试加法正常运算") public void testAdd(){ int result = Calculator.add(2,4); System.out.println(result); Assertions.assertEquals(result,6); } @Test @DisplayName("测试减法运算") @Disabled public void testSubtraction(){ int result = Calculator.subtraction(10,6); System.out.println("减法运算结果是:" + result); Assertions.assertEquals(result,4); } @Test @DisplayName("测试乘法运算") @Order(2) public void testMultiplication(){ int result = Calculator.multiplication(2,4); System.out.println("乘法运算结果是:" + result); Assertions.assertEquals(result,8); } @Test @DisplayName("测试除法运算") @Order(3) public void testDivision(){ int result = Calculator.division(10,3); System.out.println("除法运算结果是:" + result); Assertions.assertEquals(result,3); } @AfterEach public void afterEach(){ System.out.println("Calculator test After each"); } @AfterAll public static void afterAll(){ System.out.println("Calculator test After All"); } } @Nested 嵌套测试 public class NestedDemoTest { @Test @DisplayName("外层测试") public void testOuter(){ System.out.println("outer...."); } @DisplayName("内层测试") @Nested class Inner01{ @Test @DisplayName("inner01 test") public void test(){ System.out.println("inner01"); } @Nested @DisplayName("inner01 嵌套") class InInner{ @Test public void test(){ System.out.println("inner01 嵌套inner 01"); } } } @Nested @DisplayName("inner02") class Inner02{ @Test @DisplayName("inner02 test") public void test(){ System.out.println("inner02"); } } }

@Nested 用例,然后再执行第二层嵌套的用例: 外层->倒叙嵌套->第二层嵌套

junit5 断言体系 Assertions.assertEquals() 判断两个值是否相等Assertions.assertNotEquals() 判断两个值是否不相等Assertions.assertNull() 判断是否为空Assertions.asserNotNull() 判断是否不为空Assertions.assertSame() 判断两个对象的内存地址引用值是否相同Assertions.assertNotSame() 判断两个对象的内存地址引用值是否不相等assertTrue(Condition condition) 断言值为trueasserFalse(Condition condition) 断言值为false

Junit5 软断言的支持,软断言是指第一步校验不过,还可以继续向下校验

Assertions.assertAll(Executable… excutable) Executable 是一个函数式接口,可以通过lambda 表达式进行传值, …代表可变参数列表

Assertions.assertAll(() -> Assertions.assertEquals(result,5)); 多线程并发测试

在resources 目录下新建junit 配置文件 junit-platform.properties https://junit.org/junit5/docs/current/user-guide/#writing-tests-parallel-execution

# 是否允许并行测试 true/false junit.jupiter.execution.parallel.enabled=true # 是否允许测试方法并行执行,same_thread 同一线程执行, concurrent 多线程并发执行 junit.jupiter.execution.parallel.mode.default=concurrent # 是否允许测试类之间的并发执行 junit.jupiter.execution.parallel.mode.classes.default = same_thread # 配置并行策略fixed 或者dynamic 使用fixed 需要自行配置多线程并发执行数 junit.jupiter.execution.parallel.config.strategy = fixed junit.jupiter.execution.parallel.config.fixed.parallelism = 2

在测试用例上用@RepeatTest 注解来实现并发允许

@RepeatedTest(10) public void testCount() throws InterruptedException { int result = Calculator.count(1); System.out.println(result); } 测试套件的运行以及指定测试类

参考: https://junit.org/junit5/docs/current/user-guide/#testkit-engine

在pom.xml 文件中添加依赖 org.junit.platform junit-platform-suite-api test org.junit.platform junit-platform-suite-engine test 在测试类中添加@Suit 注解创建测试套 import org.junit.platform.suite.api.SelectPackages; import org.junit.platform.suite.api.Suite; import org.junit.platform.suite.api.SuiteDisplayName; @Suite @SuiteDisplayName("批量测试套") @IncludeClassNamePatterns("*Test") @IncludeTags({}) @SelectClasses({}) @ExcludeClassNamePatterns("") @ExcludePackages({}) @ExcludeTags({}) @SelectPackages({"com.huawei.test"}) public class SuitDemo { } @Suite创建测试套件@SuiteDisplayName测试套命名@SelectClass()选择加入测试套的用例@SelectPackage()选择包下面的所有用例@IncludeClassNamePatterns("*Test")选择运行类名包含Test@ExcludeClassNamePatterns("")排除类名符合某种规则@ExcludePackages({})排除选择的包@ExcludeTags({})排除被Tag 标记的测试用例 命令行 利用mvn test 和Maven Surefire plugin 插件做测试用例的执行管理 mvn test 执行全量的用例mvn -Dtest=${TestClass} test 指定测试用例运行 如 mvn -DTest =SuitDemo testmvn -Dtest= T e s t C l a s s 1 , {TestClass1}, TestClass1,{TestClass2} test 指定多个测试类运行mvn -Dtest=${*TestClass} 通过匹配的方式指定测试类的运行mvn -Dtest=KaTeX parse error: Expected 'EOF', got '#' at position 12: {TestClass}#̲{TestMethod} 指定测试方法运行 用例参数化 public class ParamDemoTest { @ParameterizedTest @ValueSource(ints={1,3}) public void testCount(int x) throws InterruptedException { int result = Calculator.count(x); System.out.println(result); } @ParameterizedTest @CsvSource(value = {"zhangsan,22,男","lisi,33,女"}) public void testCsv(String arg1 ,String arg2,String arg3){ System.out.println("arg1:" + arg1); System.out.println("arg2:" + arg2); System.out.println("arg3:" + arg3); } @ParameterizedTest @CsvFileSource(resources = "/data/user.csv") public void testCsvFile(String arg1 ,String arg2){ System.out.println("arg1:" + arg1); System.out.println("arg2:" + arg2); } /** * @MethodSource 指定数据源的来源方法,方法的返回值可以时Array List Stream 等可迭代的对象 */ @ParameterizedTest @MethodSource(value = {"getData"}) public void testMethod(String arg){ System.out.println(arg); } @ParameterizedTest @MethodSource(value = {"getMap"}) public void testMethod1(Map.Entry entry){ System.out.println(entry.getKey()); System.out.println(entry.getValue()); } public void testGetYaml(){ } static Iterator getMap(){ HashMap map = new HashMap(); map.put("name","zhangsan"); map.put("sex","男"); return map.entrySet().iterator(); } static Stream getData(){ return Stream.of("zhangsan","lisi"); } @Test public void testYaml() throws IOException { ObjectMapper objectMapper = new ObjectMapper(new YAMLFactory()); // TypeReference typeReference = new TypeReference() { // } TypeReference typeReference = new TypeReference() { }; List yamlData = objectMapper.readValue(this.getClass().getResourceAsStream("/data/testdata.yaml"),typeReference); yamlData.forEach((data) ->{ System.out.println(data.username + data.age); }); } } 利用Jackson + yaml 实现参数化步骤:

参考链接:https://www.baeldung.com/jackson-yaml

pom.xml 文件中添加Jackson 的依赖包

com.fasterxml.jackson.core jackson-databind 2.9.8

添加jackson 支持yaml的依赖包

com.fasterxml.jackson.dataformat jackson-dataformat-yaml 2.9.8

编写yaml

- username: zhangsan age: 20 computers: - brand: 华为 price: 19999 - brand: 小米 price: 9999.9 action: eat: 大鱼大肉 sleep: 10小时 map: id: 001 step: 向后走 - username: lisi age: 30 computers: - brand: mac price: 29999 action: eat: 青菜萝卜 sleep: 10小时 map: id: 002 step: 向前走 //yaml 以缩进代表层级关系 不允许tab 以两个空格代表缩进

定义对应格式的实体类,注意如果属性是私有属性提供响应get/set 方法

@JsonIgnoreProperties(ignoreUnknown = true) public class YamlData { private String username; private int age; private List computers; private Action action; private HashMap map; //get/set 方法省略.... }

编写相应的测试类

@Test public void testYaml() throws IOException { ObjectMapper objectMapper = new ObjectMapper(new YAMLFactory()); // TypeReference typeReference = new TypeReference() { // } TypeReference typeReference = new TypeReference() { }; List yamlData = objectMapper.readValue(this.getClass().getResourceAsStream("/data/testdata.yaml"),typeReference); yamlData.forEach((data) ->{ System.out.println(data.username + data.age); }); } } Junit + allure 测试报告展示 allure 环境准备

官方参考连接:https://github.com/allure-examples

参考连接:https://blog.csdn.net/huggh/article/details/90905845

Allure 安装下载地址:

https://repo1.maven.org/maven2/io/qameta/allure/allure-commandline/

下载完成之后解压,加bin目录加载到环境变量path中本地电脑需要具备java 环境

Allure 命令

Allure --help 帮助

Allure --version 查看版本信息

Allure serve 生成在线版本的测试

allure generate -o 输出目录

@Feature模块名称@Story用例名称@DisplyaName用例标题@Issue缺陷地址@Step操作步骤@Severity用例等级,blocker、critical、normal、minor、trivial@link定义连接Allure.addAttachment附件 UTF-8 UTF-8 1.8 1.8 1.8 1.9.1 2.13.6 5.7.0 org.junit.jupiter junit-jupiter-api ${junit5.version} org.junit.jupiter junit-jupiter-engine ${junit5.version} org.junit.jupiter junit-jupiter-params ${junit5.version} io.qameta.allure allure-junit5 ${allure.version} org.slf4j slf4j-simple 1.7.30 org.apache.maven.plugins maven-surefire-plugin 2.22.2 false -Dfile.encoding=UTF-8 -javaagent:"${settings.localRepository}/org/aspectj/aspectjweaver/${aspectj.version}/aspectjweaver-${aspectj.version}.jar" ${project.build.directory}/allure-results true true dynamic org.junit.platform junit-platform-surefire-provider 1.3.2 org.aspectj aspectjweaver ${aspectj.version} io.qameta.allure allure-maven 2.10.0 ${allure.version} ${project.build.directory}/allure-results org.apache.maven.plugins maven-compiler-plugin 3.8.1 1.8 1.8 @Attachment @Step("进行截图") public byte[] makeScreenShot() { return ((TakesScreenshot) driver).getScreenshotAs(OutputType.BYTES); } @Attachment(value = "pic", type = "image/jpg",fileExtension = "jpg") public byte[] makeScreenShot() throws IOException { InputStream resourceAsStream = this.getClass().getResourceAsStream("/image/1.jpg"); byte[] bytes = new byte[1024 * 1024]; return Arrays.copyOfRange(bytes,0,resourceAsStream.read(bytes)); } @Attachment public String makeAttach() { return "yeah, 2 is 2"; } // Allure.addAttachment("demo picture","image/jpg",this.getClass().getResourceAsStream("/image/1.jpg"),"jpg");


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3