前言👀~
上一章我们介绍了自动化测试工具Selenium,今天讲解单元测试工具JUnit
如果各位对文章的内容感兴趣的话,请点点小赞,关注一手不迷路,讲解的内容我会搭配我的理解用我自己的话去解释如果有什么问题的话,欢迎各位评论纠正 🤞🤞🤞
个人主页:N_0050-CSDN博客
相关专栏:java SE_N_0050的博客-CSDN博客 java数据结构_N_0050的博客-CSDN博客 java EE_N_0050的博客-CSDN博客
JUnit
JUnit 是针对 Java 语言的单元测试框架,前面讲的selenium3,我们通过这个工具写出来的一个个自动化测试用例会发现有很多冗余的内容代码看起来不雅观且不好管理,所以就引出了JUnit相当于我们拿着一个技术来对已经编写好的测试用例进行管理
通过selenium自动化测试工具以及junit单元测试框架结合,针对项目来实现自动化测试,有哪些亮点?
1)使用注解:避免生成过多对象,造成了资源和时间的浪费
2)通过static修饰静态变量,全局只创建一次驱动对象,避免重复创建驱动对象造成时间的浪费
3)使用参数化:保持用例的简洁,提高了代码的可读性
4)使用测试套件:一次执行所有我们想要运行的自动化用例
5)使用等待(隐式等待+强制等待):提高自动化指定的稳定性—降低自动化出现误报的概率
6) 使用屏幕截图:方便问题的追溯和问题的解决
JUnit的使用
首先添加依赖,去中央存储库中搜索
找到对应的依赖,我这边选择的是5.8.2,代码如下
<!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-api -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.8.2</version>
<scope>test</scope>
</dependency>
JUnit注解
下面对JUnit中的注解进行演示,默认使用public修饰
首先导入注解的依赖,代码如下
<dependency>
<!--注解用到的API-->
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.8.2</version>
<scope>compile</scope>
</dependency>
@Test:表示当前的这个方法是一个测试用例
public class JUnitTest {
@Test
//表示当前的这个方法是一个测试用例
void test1() {
System.out.println("我是Test注解");
}
}
@Disabled:表示忽略当前这个测试用例,直接跳过测试。方便修改这个测试用例
public class JUnitTest {
@Test
//表示当前的这个方法是一个测试用例
void test1() {
System.out.println("我是Test注解");
}
@Disabled
//表示忽略当前这个测试用例,直接跳过测试
void test2() {
System.out.println("我是Disabled注解");
}
}
输出结果,只输出了上面test1方法的内容
BeforeAll和AfterAll注解
下面两者注意使用static修饰!
@BeforeAll:表示所有测试用例在跑之前,先去执行BeforeAll注解里的代码。所以做UI自动化通常情况把创建驱动打开网页放在BeforeAll里
public class JUnitTest {
@Test
//表示当前的这个方法是一个测试用例
void test1() {
System.out.println("我是Test注解");
}
@Test
void test2() {
System.out.println("我是test2注解");
}
@BeforeAll
//所有测试用例执行之前 先执行BeforeAll里的代码
static void test3() {
System.out.println("我是BeforeAll注解");
}
}
输出结果
@AfterAll:表示所有测试用例跑完之后,再去跑AfterAll注解里的代码。关闭浏览器放在BeforeAll
public class JUnitTest {
@Test
//表示当前的这个方法是一个测试用例
void test1() {
System.out.println("我是Test注解");
}
@Test
void test2() {
System.out.println("我是test2注解");
}
@BeforeAll
//所有测试用例执行之前 先执行BeforeAll里的代码
static void test3() {
System.out.println("我是BeforeAll注解");
}
@AfterAll
//所有测试用例执行之后 再去执行AfterAll里的代码
static void test4() {
System.out.println("我是AfterAll注解");
}
}
输出结果
BeforeEach和AfterEach注解
@BeforeEach:表示每一个测试用例执行之前BeforeEach里面的代码都要执行一遍
public class JUnitTest {
@Test
//表示当前的这个方法是一个测试用例
void test1() {
System.out.println("我是Test注解");
}
@Test
void test2() {
System.out.println("我是test2注解");
}
@BeforeEach
//表示每一个方法执行前都会执行一遍BeforeEach里的内容
void test3() {
System.out.println("我是BeforeEach注解");
}
}
输出结果
@AfterEach:表示每一个测试用例执行之后AfterEach里面的代码都要执行一遍
public class JUnitTest {
@Test
//表示当前的这个方法是一个测试用例
void test1() {
System.out.println("我是Test注解");
}
@Test
void test2() {
System.out.println("我是test2注解");
}
@AfterEach
//表示每一个方法执行后都会执行一遍BeforeEach里的内容
void test4() {
System.out.println("我是AfterEach注解");
}
}
输出结果
参数化
使用@ParameterizedTest标注方法类型为参数化,然后搭配下面讲解的注解使用
使用@ParameterizedTest注解前也需要导入对应的依赖,代码如下
<dependency>
<!--参数化用到的API-->
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<version>5.8.2</version>
</dependency>
注意使用了这个注解就不要再添加@Test注解,加了的话执行的时候会抛异常!
单参数: @ValueSource(类型={参数1,参数2等}})
public class JUnitTest {
@Test
//表示当前的这个方法是一个测试用例
void test1() {
System.out.println("我是Test注解");
}
@ParameterizedTest
@ValueSource(strings = "我是ValueSource注解")
void test2(String s) {
System.out.println(s);
}
}
输出结果
使用CSV注解获取参数:注意和单参数一样只能传同种类型的参数!
@CsvFileSource:如果参数非常的多我们可以通过这个注解借助文件注入的方式来添加,路径可以指定为当前项目下resource文件中的csv文件(内容使用逗号分割),也可以指定为本地任意文件夹下的csv文件
public class JUnitTest {
@Test
//表示当前的这个方法是一个测试用例
void test1() {
System.out.println("我是Test注解");
}
@ParameterizedTest
@CsvFileSource(resources = "test.csv")
void test2(String s) {
System.out.println(s);
}
}
输出结果
多参数:上面的只能传同种类型的参数,使用多参数注解就可以传递多个不同的参数
@CsvSource:可以传递多个不同类型的参数,参数之间默认的分隔符是逗号,还能手动指定分隔符
public class JUnitTest {
@Test
//表示当前的这个方法是一个测试用例
void test1() {
System.out.println("我是Test注解");
}
@ParameterizedTest
@CsvSource(value = {"1,老六", "2,老八"})
void test2(int n, String name) {
System.out.println(n + " " + name);
}
}
输出结果
还能传入空的字符串!
public class JUnitTest {
@Test
//表示当前的这个方法是一个测试用例
void test1() {
System.out.println("我是Test注解");
}
@ParameterizedTest
@CsvSource(value = {"1,老六", "2,老八","3,''"})
void test2(int n, String name) {
System.out.println(n + " " + name);
}
}
输出结果
方法获取参数(动态参数)
使用@MethodSource注解,如果没有指定数据来源,则默认找跟用例同名的静态方法
单参数:可以就传同种类型的参数,将方法返回类型改为对应的类型即可
public class JUnitTest {
@Test
//表示当前的这个方法是一个测试用例
void test1() {
System.out.println("我是Test注解");
}
public static Stream<String> method() {
return Stream.of("坤坤", "坤舞", "坤");
}
@ParameterizedTest
@MethodSource("method")
void test2(String name) {
System.out.println(name);
}
}
输出结果
多参数:可以传不同种类型的参数
public class JUnitTest {
@Test
//表示当前的这个方法是一个测试用例
void test1() {
System.out.println("我是Test注解");
}
public static Stream<Arguments> method() {
return Stream.of(Arguments.arguments(1, "签哥"), Arguments.arguments(2, "坤哥"));
}
@ParameterizedTest
@MethodSource("method")
void test2(int n, String name) {
System.out.println(n + " " + name);
}
}
输出结果
断言
写自动化测试,测试的结果就两种要么成功要么失败,我们可以使用断言进行判断,省去那种ifelse语句
使用Assertions类调用assertEquals方法:判断预期值和实际值相等
public class JUnitTest {
@ParameterizedTest
@ValueSource(ints = 1)
void test2(int n) {
Assertions.assertEquals(2, n);
}
}
输出结果,如果不相等就会报错
使用Assertions类调用assertNotEquals方法:判断预期值和实际值不相等
public class JUnitTest {
@ParameterizedTest
@ValueSource(ints = 1)
void test2(int n) {
Assertions.assertNotEquals(1, n);
}
}
输出结果,如果相等就会报错
使用Assertions类调用assertNull方法:判断为空
public class JUnitTest {
@Test
void test2() {
String s = "s";
Assertions.assertNull(s);
}
}
输出结果,如果不空就会报错
使用Assertions类调用assertNotNull方法:判断不为空
public class JUnitTest {
@Test
void test2() {
String s = null;
Assertions.assertNotNull(s);
}
}
输出结果,如果为空就会报错
用例执行顺序
junit的默认执行顺序是不确定的 采用的是自己执行顺序对应的算法,但用例执行顺序是固定的。什么意思呢?你可以试试第一次运行的结果和后面运行的结果对比一下,下面进行演示
下面这段代码按道理应该先输出test1方法的内容,再输出A方法的内容,再输出test2方法的内容
public class JUnitTest {
@Test
void test1() {
System.out.println("这是junit测试1");
}
@Test
void A() {
System.out.println("这是junit测试A");
}
@Test
void test2() {
System.out.println("这是junit测试2");
}
}
输出结果
再运行一次输出的结果,还是一样
指定方法执行顺序:使用@TestMethodOrder(MethodOrderer.OrderAnnotation.class)注解搭配@Order注解
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class JUnitTest {
@Order(1)
@Test
void test1() {
System.out.println("这是junit测试1");
}
@Order(2)
@Test
void A() {
System.out.println("这是junit测试A");
}
@Order(3)
@Test
void test2() {
System.out.println("这是junit测试2");
}
}
输出结果
方法随机执行顺序:使用@TestMethodOrder(MethodOrderer.Random.class)注解
@TestMethodOrder(MethodOrderer.Random.class)
public class JUnitTest {
@Test
void test1() {
System.out.println("这是junit测试1");
}
@Test
void A() {
System.out.println("这是junit测试A");
}
@Test
void test2() {
System.out.println("这是junit测试2");
}
}
输出结果
为什么需要用到junit里的排序方法呢?
如果用例之间存在关联关系的话就需要手动指定用例的执行顺序
测试套件
首先也要导入对应的依赖,代码如下
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-suite</artifactId>
<version>1.8.2</version>
<scope>test</scope>
</dependency>
使用@Suite注解:表示当前类是个测试套件,搭配下面的注解使用
使用@SelectClasses可以通过指定类的方式 添加到套件中并执行里面的所有测试用例
@Suite
@SelectClasses({Test01.class, Test02.class})
public class JUnitTest {
}
输出结果
使用@SelectPackages可以通过指定包的方式 添加到套件中并执行测试用例
@Suite
@SelectPackages(value = {"Test1", "Test2"})
public class JUnitTest {
}
输出结果
以上便是本章内容关于JUnit一些概念和使用,在自动化测试中还是尤为重要的一部分,我们下一章再见💕