作为一款测试框架,一般我们需要从以下几个方面去考虑
junit5 大体由3个模块组成
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");
}
}
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.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 标记的测试用例 |
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);
});
}
}
参考链接: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);
});
}
}
官方参考连接:https://github.com/allure-examples
参考连接:https://blog.csdn.net/huggh/article/details/90905845
Allure 安装下载地址:
https://repo1.maven.org/maven2/io/qameta/allure/allure-commandline/
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");