Junit 5 单元测试框架
目录
1. Junit 5 的依赖
2. Junit - 注解
2.1 @Test
2.2 @BeforeEach
2.3 @BeforeAll
2.4 @AfterEach
2.5 @AfterAll
3. Junit - 断言
3.1 assertEquals/ assertNotEquals 断言是否匹配
3.2 assertTrue / assertFalse 断言结果的真假
3.3 assertNull / assertNotNull 断言结果是否为空
4. Junit - 测试用例的执行顺序
5. Junit - 参数化
5.1 单参数数据来源
5.2 多参数数据来源 - 在注解里编写数据源
5.3 多参数数据来源 - 从第三方 csv 文件读取数据源
5.4 多参数数据来源 - 通过动态方法来提供数据源
6. JUnit - 测试套件
6.1 指定类来运行用例
6.2 指定包名来运行包下所有的用例
1. Junit 5 的依赖
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.8.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-suite</artifactId>
<version>1.8.2</version>
<scope>test</scope>
</dependency>
如果之前已经下载过 Junit 4 的相关依赖, 那么则需要先删除本地仓库的依赖, 再下载 Jnit5 的依赖.
2. Junit - 注解
2.1 @Test
该注解是用来加在测试的方法上面的, 表示该方法是测试方法, 并且当我们给方法加上 @Test 注解的时候, 当前方法就可以自己运行了, 不再需要 main 函数来调用. 而且当前类也可以自己运行了 , 运行当前类表示执行当前类里面所有加了 @Test 注解的方法.
不使用 @Test 注解之前, 测试方法需要的步骤 :
第一步 : 编写测试类, 编写测试方法.
第二步 : 编写运行测试类, 添加 main 方法, 实例化测试类, 调用相关测试方法.
使用 @Test 注解之后, 测试方法需要的步骤 :
由此对比, 使用 Junit 提供的注解来辅助自动化测试, 大大简化了代码的编写, 更加的方便了测试人员更好的进行测试.
并且, 在一个测试类中, 你想让哪些方法执行, 就在该方法上加 @Test 注解即可, 不想让它执行, 就去掉 @Test 注解即可, 非常方便.
执行结果 :
2.2 @BeforeEach
该注解是修饰方法的, 当一个测试方法加上 @BeforeEach 注解之后, 就表示当前方法需要在每个测试用例执行之前都执行一次. (注意加上 @BeforeEach 注解之后, 就不要加 @Test 注解了)
代码示例 :
public class JunitTest {
@BeforeEach
void baseController() {
System.out.println("before each");
}
@Test
void base1() {
System.out.println("bbb");
}
@Test
void base2() {
System.out.println("ccc");
}
}
执行结果 :
2.3 @BeforeAll
该注解是修饰方法的, 当一个测试方法加上 @BeforeAll 注解之后, 就表示当前方法需要在当前类下所有测试用例执行之前执行一次. 并且被该注解修饰的方法必须为静态方法.
在测试项目的时候, 可以把创建驱动对象单独写一个方法, 使用 @BeforeAll 注解修饰.
代码示例 :
public class JunitTest {
@BeforeAll
static void baseController() {
System.out.println("before all");
}
@Test
void base1() {
System.out.println("bbb");
}
@Test
void base2() {
System.out.println("ccc");
}
}
执行结果 :
2.4 @AfterEach
该注解是修饰方法的, 当一个测试方法加上 @AfterEach 注解之后, 就表示当前方法需要在每个测试用例执行之后都执行一次.
代码示例 :
public class JunitTest {
@AfterEach
void baseController() {
System.out.println("after each");
}
@Test
void base1() {
System.out.println("bbb");
}
@Test
void base2() {
System.out.println("ccc");
}
}
执行结果 :
2.5 @AfterAll
该注解是修饰方法的, 当一个测试方法加上 @AfterAll 注解之后, 就表示当前方法需要在当前类下所有测试用例执行之后执行一次. 并且被该注解修饰的方法必须为静态方法.
在测试项目的时候, 可以把释放驱动对象单独写一个方法, 使用 @AfterAll 注解修饰.
代码示例 :
public class JunitTest {
@AfterAll
static void baseController() {
System.out.println("after all");
}
@Test
void base1() {
System.out.println("bbb");
}
@Test
void base2() {
System.out.println("ccc");
}
}
执行结果 :
3. Junit - 断言
3.1 assertEquals/ assertNotEquals 断言是否匹配
例如我们获取一下百度首页中百度一下按钮上的文字 - 百度一下, 假如我们的预期结果是百度两下, 而打印的是百度一下, 此时就可以使用 assertEquals 来断言是否匹配. 该方法有两个参数, 第一个参数是预期结果, 第二个参数是实际结果.
代码示例 :
@Test
void baseAssert() {
EdgeDriver driver = new EdgeDriver();
driver.get("https://www.baidu.com");
// 获取百度一下按钮上属性对应的值 - 百度一下
String text = driver.findElement(By.cssSelector("#su"))
.getAttribute("value");
System.out.println("预期结果: 百度两下, 实际结果 : " + text);
// 断言匹配
Assertions.assertEquals("百度两下", text); // false
// 断言不匹配
// Assertions.assertNotEquals("百度两下", text); // true
driver.quit();
}
执行结果 :
使用 assertNotEquals 断言不匹配, 程序执行结果 :
3.2 assertTrue / assertFalse 断言结果的真假
代码示例 :
@Test
void baseAssert1() {
Assertions.assertTrue(1 == 1); // true
}
@Test
void bassAssert2() {
Assertions.assertTrue(1 == 0); // false
}
@Test
void bassAssert3() {
Assertions.assertFalse(1 == 1); // false
}
@Test
void bassAssert4() {
Assertions.assertFalse(1 == 0); // true
}
执行结果 :
3.3 assertNull / assertNotNull 断言结果是否为空
代码示例 :
@Test
void baseAssert5() {
String res = null;
Assertions.assertNull(res);
}
@Test
void baseAssert6() {
String res = "hello";
Assertions.assertNull(res);
}
执行结果 :
4. Junit - 测试用例的执行顺序
先来看默认情况下, 多个测试用例的执行顺序.
代码示例 :
public class JunitTest {
@Test // 2
void editLoginTest() {
System.out.println("loginTest");
}
@Test // 1
void indexTest() {
System.out.println("indexTest");
}
@Test // 3
void editTest() {
System.out.println("editTest");
}
}
执行结果 :
从执行结果来看, 默认情况下, 多个测试用例的执行顺序是随机的 (可以调整顺序, 多运行几次) . 那么有时候我们一些登录的场景, 是需要按照顺序进行测试的, 比如说博客的登录系统, 我们要登录之后, 才能进入到博客列表页, 博客编辑页, 此时就需要针对多个测试用例指定执行顺序了.
使用 @Order 注解来指定多个测试用例的执行顺序 :
1. 先要使用 @TestMethodOrder 注解来说明当前类下所有的用例需要使用 Order 注解来进行排序, 当然也可以根据方法名排序, 但是常用的还是 Order 指定方法排序.
2. 然后通过 @Order 注解来指定测试用例的具体顺序.
3. @Test 注解不能删除.
代码示例 :
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class JunitTest {
@Test
@Order(1)
void editLoginTest() {
System.out.println("loginTest");
}
@Test
@Order(2)
void indexTest() {
System.out.println("indexTest");
}
@Test
@Order(3)
void editTest() {
System.out.println("editTest");
}
}
执行结果 :
5. Junit - 参数化
在登录场景中, 如果我们不使用参数化, 那么多个用户登录的时候, 我们的测试用例写起来就会非常麻烦, 如下 :
而我们期望的是尽可能的通过一个测试用例, 多组参数来模拟用户的登录行为.
1. 在使用参数化注解之前需要先使用 @ParamterizedTest 声明该方法为参数化方法.
2. 通过注解提供数据来源.
5.1 单参数数据来源
使用 @ValueSource 注解
@ValueSource(数据类型方法 = {参数1, 参数2, 参数3 .....})
@ParameterizedTest
@ValueSource(strings = {"张三", "李四", "王五"})
void singleParamTest(String name) {
System.out.println(name);
}
执行结果 :
5.2 多参数数据来源 - 在注解里编写数据源
使用 @CsvSource 注解.
@CsvSource({"第一组数据", "第二组数据", "第三组数据", ....}) , 每一个双引号, 就是一组测试用例.
@ParameterizedTest
@CsvSource({"张三, 123","李四, 123", "王五, 123"})
void muchParamTest(String name, int age) {
System.out.println("name: " + name + ", age : " + age);
}
执行结果 :
5.3 多参数数据来源 - 从第三方 csv 文件读取数据源
多参数场景下, 当在注解中的测试用例越来越多时, 代码的可读性就会非常差, 此时可以使用 @CsvFileSource 注解来从第三方 csv 文件中读取数据源.
@CsvFileSource(files = "文件路径")
@ParameterizedTest
@CsvFileSource(files = "D:\\aa\\abc.csv")
void csvFileParamTest(String name, int age) {
System.out.println("name: " + name + ", age : " + age);
}
执行结果 :
5.4 多参数数据来源 - 通过动态方法来提供数据源
使用 @MethodSource 注解
@ParameterizedTest
@MethodSource("methodParams")
void dynamicMethodParamTest(String name, int age) {
System.out.println("name : " + name + ",age : " + age);
}
static Stream<Arguments> methodParams() throws InterruptedException {
// 构造动态参数
String[] array = new String[5];
for(int i = 0; i < array.length; ++i) {
Thread.sleep(500);
array[i] = String.valueOf(System.currentTimeMillis());
}
return Stream.of(
Arguments.arguments(array[0], 21),
Arguments.arguments(array[1], 22),
Arguments.arguments(array[2], 23),
Arguments.arguments(array[3], 24),
Arguments.arguments(array[4], 25)
);
}
执行结果 :
此处指定的方法的返回类型 Arguments, 是因为一组数据的数据类型不同, 由 String 和 int 类型组合来的, 因此要使用组合类型 Arguments. 如果相同, 就可以写具体的类型.
【其他注意事项]
1. 当我们不指定数据源方法名时, 会自动的找跟用例方法名同名的静态方法.
2. 使用了参数化注解的方法不能再用 @Test 注解. (@Test 只能作用在非参数化的用例上)
6. JUnit - 测试套件
测试套件是用来指定当前包下哪些类中测试方法需要被执行, 如果没有测试套件, 我们很难去同时执行几个类下的测试用例.
准备工作 : 在 autoTest5 包下创建 aaa, bbb, ccc, 三个测试类, 分别给每个类加上测试方法, 以及前面创建好的 JunitTest 测试类.
6.1 指定类来运行用例
创建 runSuite 测试套件类, 添加@Suite注解, @SelectClasses 注解, 指定类运行类下的加了 @Test 注解, 或者参数化的测试用例.
@Suite
@SelectClasses({aaa.class,ccc.class})
public class runSuite {
}
运行测试套件, 执行结果 :
6.2 指定包名来运行包下所有的用例
此时 autoTest5 包下有如下几个类 :
改写测试套件代码 :
@Suite
@SelectPackages("com.autoTest5")
public class runSuite {
}
执行结果 :
autoTest5 包下明明有 4 个类, 为啥只运行了一个类中的测试用例呢 ?
如果使用包名来指定运行的范围, 那么该包下所有测试类的命名必须要以 Test/Tests 结尾 (T 必须要大写)
改类名 :
执行结果 :
本篇文章就到这里了, 谢谢观看~