测试框架
第一章 Junit5测试框架实战
提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
一、xUnit体系结构
二、java语言的xUnit主流框架
三、Junit5实战
1、第一个Junit5脚本
步骤
1、新建一个maven项目
2、添加依赖
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.7.0</version>
<scope>test</scope>
</dependency>
3、编写脚本测试环境
public class EnvTest {
@Test
public void envTest(){
assertEquals(1,2,"预期和实际值不符");
}
}
2、 断言
2.1、junit常用断言方式
2.2、关于断言的新问题
有一个方法存在多个断言,但是其中一个断言失败了,后面的断言都没有执行,难道我要等第一个问题修好了才能继续检查后面的断言吗?
2.3、问题原因分析及改进方案
- 问题原因:因为原来使用的是junit5的普通断言,当一个断言失败会直接跳出测试方法,导致后面的断言无法执行,此时的脚步容错性较低。
- 解决思路:
- 拆开多个测试方法,每个测试方法进行一个断言。(会造成大量重复代码,此方法被否)
- 使用软断言,即使一个断言失败,扔会进行余下的断言,然后统一输出所有断言结构。
- 实施方案:
- 可以使用Junit5提供的Java 8 lambdas的断言方法,当一个亿失败,剩下的断言依然会执行,脚本的容错性增强。
2.4、Juint5带来新的断言方式
assertAll断言方法,会在执行完多余断言后统一输出结构,一次性暴露所有问题,提高了测试脚本的健壮性。
3、动态测试
3.1、一个非常规的问题解决
- 问题描述:
运维团队有一批做线上配置检查脚本,领导希望将他们的测试结构整合到我们的junit测试报告里,他们有几千条测试用例,而且是shell写成,使用java重写工作量巨大。 - 问题原因分析及改进方案
- 问题原因:传统自动化测试思路中,我们的测试逻辑是在以硬编码的形式组织到代码里的,当遇到用例迁移或结果整合时,会产生大量的逻辑重写
- 解决思路:我们除了硬编码的脚本编写方式外,还要能动态地在脚本Runtime时生成用例
- 实施方案:junit5提供了动态测试方案,让测试人员可以在脚本Runtime时动态的批量生成用例
- 官方给出的DynamicTest示例
class DynamicTestsDemo { private final Calculator calculator = new Calculator(); // This will result in a JUnitException! @TestFactory List<String> dynamicTestsWithInvalidReturnType() { return Arrays.asList("Hello"); } @TestFactory Collection<DynamicTest> dynamicTestsFromCollection() { return Arrays.asList( dynamicTest("1st dynamic test", () -> assertTrue(isPalindrome("madam"))), dynamicTest("2nd dynamic test", () -> assertEquals(4, calculator.multiply(2, 2))) ); } @TestFactory Iterable<DynamicTest> dynamicTestsFromIterable() { return Arrays.asList( dynamicTest("3rd dynamic test", () -> assertTrue(isPalindrome("madam"))), dynamicTest("4th dynamic test", () -> assertEquals(4, calculator.multiply(2, 2))) ); } }
4、并发测试
4.1 线程安全问题原理
什么是线程安全?通俗地说,就是保证多个线程同时对某一个对象进行操作时不会出错。比如两个客户端,同时堆某个课程进行报名操作并记录总数,如果不加以并发控制,那么就会出现堆当前报名总数脏读的情况
4.2 实际案例背景
当服务器hi分布式集群形式时,会产生一个问题,当多个订课请求打到不同的服务器上,而多个服务器堆已定课程总数的读取过程中产生脏读的问题,就叫做分布式锁问题
4.3 问题抽象
线程安全性问题出现的三个必要条件
1-多线程环境下
2-多个线程共享同一个资源
3-堆资源进行非原子性操作
4.4 常见线程安全问题场景
4.5 junit5的并发测试
junit测试是在一个线程中串行执行的,从5.3开始支持并行测试。
首先需要在配置文件junit-platorm.properties中配置
#是否允许并行执行true/false
junit.jupiter.execution.parallel.enabled=true
#是否支持方法级别多线程same_thread/concurrent
junit.jupiter.execution.parallel.mode.default=concurrent
#是否支持类级别多线程same_thread/concurrent
junit.jupiter.execution.parallel.mode.classes.default=concurrent
# the maximum pool size can be configured using a ParallelExecutionConfigurationStrategy
junit.jupiter.execution.parallel.config.strategy=fixed
junit.jupiter.execution.parallel.config.fixed.parallelism=4
4.6 线程安全问题修复思路
- Synchronized:
- 保证方法内部或代码块内部资源(数据)的互斥访问。即统一时间、由同一个最多只能有一个线程在访问。(破坏多线程环境)
- java.util.concurrent.atomic:
- 包提供了一系列的AtomicBoolean、AtomicInteger、AtomicLong等类。使用这些类来声明变量可以保证堆其操作具有原子性来保证线程安全。(破坏操作的非原子性)
1)分布式线程安全问题修复思路
2)并发场景测试与性能测试的区别
3)数据库锁原理
- 表锁定:更新/删除操作会添加排他锁。此类操作的where条件如果未添加索引会升级为表级锁定,导致其他逻辑堆该表的操作失败。
- 事务中死锁:两个事务都持有对方需要的锁,并且在等待对方释放,并且双方都不会释放自己的锁。
4)混合并发场景实际案例
当我们在进行混合场景测试时,发现当分发任务执行时,会有大量的线索收集操作大量超时报错,最后经排查是因为更新发布结构逻辑包含未加索引的索引条件后升级为表锁。导致新线索的插入操作超时报错。
5.测试报告
5.1 Allure2环境准备
- 第一步:添加maven依赖
<dependency>
<groupId>io.qameta.allure</groupId>
<artifactId>allure-junit5</artifactId>
<version>2.13.2</version>
<scope>test</scope>
</dependency>
- 第二步:下载allure2工具并配置环境变量
- 下载好后,环境变量配置到allure的bin目录下为止,然后cmd中可以allure --version查看配置是否成功
- 第三步:allure2 工具创建本地jetty服务器实例
allure server allure-results
5.2 Allure2常用注解
附录
代码地址