jck28 - 小柒 - Junit5测试框架L1学习笔记

1,简介

主要由三个部分组成:

  • JUnit Platform
  • JUnit Jupiter
  • JUnit Vintage

maven依赖:

<dependencies>
    <dependency>
    <!-- JUnit5 新的编程和扩展模型 -->
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter</artifactId>
        <version>5.8.2</version>
        <scope>test</scope>
    </dependency>
</dependencies>
<build>
<!-- maven 运行的依赖插件 -->
    <plugins>
        <plugin>
            <artifactId>maven-surefire-plugin</artifactId>
            <version>2.22.2</version>
        </plugin>
        <!-- 无需使用此插件,容易版本冲突,加载不起来 -->
        <!-- <plugin>
            <artifactId>maven-failsafe-plugin</artifactId>
            <version>2.22.2</version>
        </plugin> -->
    </plugins>
</build>

2,命名规则

  • 单元测试代码文件

    • 默认写在工程目录: src/test/java
    • 不允许写在业务代码目录下(src/main/java是业务代码目录)
  • 测试资源文件

    • 默认写在资源目录:src/test/resources
      *文件默认命名规则:以Test开头或者以Test结尾的java文件
    • 也可以使用 surefire 插件自定义命名规则,需要导入maven依赖:
  • 使用maven依赖配置的文件,默认Test开头或者结尾的规则就会失效

<plugin>
<!-- 某些版本需要添加groupId,否则报错 -->
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>3.0.0-M5</version>
    <configuration>
        <includes>
            <include>**/*Hogwarts*.java</include>
            <include>**/*TestCase.java</include>
        </includes>
    </configuration>
</plugin>

3,测试用例结构

  • 使用 @Test 注解表示为测试方法 ——如果不加@Test标识,这条用测不会被执行

  • 使用 @DisplayName 定义别名 —— 测试用例增多,为了方便识别每个测试用例

  • 使用 Assertions 类的断言方法进行测试用例的断言

4,常用注解

  • @Test 注解表示为测试方法

  • @DisplayName 定义别名

  • @BeforeEach 在每个用例执行前都会执行这一条用例

  • @AfterEach 在每个用例执行后都会执行这一条用例

  • @BeforeAll 在所有用例执行前会执行这一条,被装饰的方法必须加上static

  • @AfterAll 在所有用例执行后会执行这一条,被装饰的方法必须加上static

  • @Tag 为测试类或者方法添加标签

  • @RepeatedTest(n) 表示需要重复执行的用例,参数n表示需要再重复执行n次

  • @Order(n) 定义执行顺序,需要在测试类上打上@TestMethodOrder(MethodOrderer.OrderAnnotation.class)注解

  • @Disabled 会跳过这条用例不执行

package JUnit5Demo;

import org.junit.jupiter.api.*;

import static org.junit.jupiter.api.Assertions.assertEquals;

@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class TestAssertion {

    @BeforeEach
    void fn(){
        System.out.println("在每个用例前都会执行");
    }

    @AfterEach
    void after(){
        System.out.println("在每个用例后都会执行");
    }

    @BeforeAll
    static void ball(){
        System.out.println("在所有用例前只执行一次=================");
    }

    @AfterAll
    static void afterall(){
        System.out.println("在所有用例后只执行一次******************");
    }

    @Test
    @DisplayName("testAssertion用例")
    @Tag("这是一条主用例")                 
    void testAseertion(){
        System.out.println("Hogwarts~");
        // 利用断言,判断方法的实际执行结果和预期结果是否一致
        // 第一个参数表示预期结果,第二个参数表示实际结果。
        assertEquals(2,1+1);
//        assertEquals(2,1+2);            //结果为false时会报错
    }

    @Test
    @DisplayName("testOne用例")
    @RepeatedTest(3)                  //@RepeatedTest注解表示需要重复执行的用例,参数3表示需要再重复执行3次
    void testOne(){
        System.out.println("执行testOne用例");
    }

    @Test
    @DisplayName("testTwo用例")
    @Order(1)    //定义执行顺序,需要在测试类上打上@TestMethodOrder(MethodOrderer.OrderAnnotation.class)注解
    void testTwo(){
        System.out.println("执行testTwo用例");
    }

    @Test
    @Disabled                         //@Disabled注解,会跳过这条用例不执行
    void test01(){
        System.out.println("执行test01用例");
    }

}

5,测试用例断言
断言有两种方法:

  • 内置断言方法
  • 必修
    • assertEquals
    • assertTrue
    • assertAll
  • 选修
    • assertNotNull
    • assertTimeout
    • assertThrows
  • 第三方库断言
    • Hamcrest
    • AssertJ
    • Truth
package JUnit5Demo;

import org.junit.jupiter.api.Test;
import java.time.Duration;
import static java.lang.Thread.sleep;
import static org.junit.jupiter.api.Assertions.*;
import static org.junit.jupiter.api.Assertions.assertAll;

public class AssertTest {
    //JUnit5有两种断言方法:内置断言方法Assertion和第三方库断言
    @Test
    void testEquals(){
        assertEquals(2,1+1);
//        assertEquals(2,1+2);
        //断言对象是表达式
        assertTrue(3 > 1);
        //断言对象是布尔类型
        assertTrue(true);
        // 断言对象如果不是null则返回true
        assertNotNull("hog");
        // 断言对象如果是null则返回false,报错
//        assertNotNull(null);
    }

    @Test
    void assertAllDemo(){
        //如果同一个方法有多个断言对象,其中一个断言失败报错,则不会再往后执行其他的断言,这时候需要用assertAll()方法来进行断言
        //assertAll()分组断言,也叫软断言,这种断言方式即使中间报错,也会执行完所有断言方法
        assertAll("分组断言",
                () ->assertEquals(2,1+1),
                () ->assertEquals(2,1+3),
                () -> assertTrue(3 >1));
    }

    @Test
    void timeoutTest(){
        //超时断言,它只会比较方法内地2个参数值是否小于Duration.ofSeconds()的值,小于则为true,大于则会fasle
        assertTimeout(Duration.ofSeconds(3), () ->sleep(2000));
    }


    void fun(int a, int b){
        System.out.println(a/b);
    }

    @Test
    void exceptTest(){
        //异常断言,抛了异常才是true,不抛异常就会断言失败报错
        assertThrows(ArithmeticException.class, () ->fun(1,0));
    }

}

6,测试框架结构
测试类之间的继承关系:

  • SubTest类继承自BaseTest类,如果SubTest类的方法与BaseTest类一样,则重写了父类方法,执行用例只会打印子类的用例结果

  • SubTest类的方法与BaseTest类不一样,执行BaseTest类,会打印BaseTest类和SubTest类的用例执行结果

  • 执行顺序:父类优先级高于子类,先开始的后结束

  • beforeAllA > beforeAllB > beforeEachA > beforeEachB > method1,2,3,4 > afterEachB > afterEachA > afterAllB > afterAllA

  • JUnit5注解的继承关系,详细可以参考官网文档:https://junit.org/JUnit5/docs/current/user-guide/

package frameDemo;

import org.junit.jupiter.api.*;
public class BaseTest {

    @BeforeAll
    public static void beforeAllA(){
        System.out.println("执行BaseTest —— beforeAllA !");
    }

    @AfterAll
    public static void afterAllA(){
        System.out.println("执行BaseTest —— afterAllA !");
    }

    @BeforeEach
    public void beforeEachA(){
        System.out.println("执行BaseTest —— beforeEachA !");
    }

    @AfterEach
    public void afterEachA(){
        System.out.println("执行BaseTest —— afterEachA !");
    }

    @Test
    public void method1(){
        System.out.println("执行BaseTest —— method1 !");
    }

    @Test
    public void method2(){
        System.out.println("执行BaseTest —— method2 !");
    }


}

SubTest类继承自BaseTest:

package frameDemo;

import org.junit.jupiter.api.*;

public class SubTest extends BaseTest{

    @BeforeAll
    public static void beforeAllB(){
        System.out.println("执行SubTest —— beforeAllB !");
    }

    @AfterAll
    public static void afterAllB(){
        System.out.println("执行SubTest —— afterAllB !");
    }

    @BeforeEach
    public void beforeEachB(){
        System.out.println("执行SubTest —— beforeEachB !");
    }

    @AfterEach
    public void afterEachB(){
        System.out.println("执行SubTest —— afterEachB !");
    }

    @Test
    public void method3(){
        System.out.println("执行SubTest —— method3 !");
    }

    @Test
    public void method4(){
        System.out.println("执行SubTest —— method4 !");
    }

}

7,测试用例调度与运行

  • maven 对应有默认配置: maven-surefire-plugin

  • 当需要修改一些测试相关执行策略的时候,就需要重新配置这个插件

  • 执行测试用例的两种方式

    • 命令行执行 :
      mvn test ——执行当前项目下的所有测试
      mvn test -Dtest=包名.类名 ——执行单个测试类
      mvn test -Dtest=包名.类名#方法名 ——执行单个测试方法
      mvn test -Dtest=包名.类名#方法名1+方法名2 ——执行多个测试方法
      mvn test -Dtest=包名.类名1,包名.类名2,… ——执行同一个包下面的测试类
      mvn test -Dtest=包名1.类名1,包名2.类名2,… ——执行不同包下面的测试类
      mvn test -Dtest=“包名.*Test” ——正则匹配执行多个测试类

    • 配置文件执行: 包名之间用/区分, 对应写法有3种方式,用哪种都可以

执行单个测试类的配置:

<!-- 可以是类名.java -->
 <include>包名/类名.java</include>

 <!-- 可以直接是类名 -->
 <include>包名/类名</include>

 <!-- 可以是类名.class -->
 <include>包名/类名.class</include>
执行同一个包下面的测试类:

 <!-- 可以是包名.java -->
<include>包名1/*.java</include>

  <!-- 可以直接是包名 -->
<include>包名1/*</include>

  <!-- 可以是包名.class -->
<include>包名1/*.class</include>
执行不同包下面的测试类:

<!-- 可以是类名.java -->
 <include>包名1/类名1.java</include>
 <include>包名2/类名2.java</include>
 ...
  <!-- 可以直接是类名 -->
 <include>包名1/类名1</include>
 <include>包名2/类名2</include>
 ...
 <!-- 可以是类名.class -->
 <include>包名1/类名1.class</include>
 <include>包名2/类名2.class</include>

正则匹配执行多个测试类:

<include>包名/*Test</include>

<include>包名/*Test.java</include>

<include>包名/*Test.class</include>
配置不被执行的测试类:

<exclude>包名/*Test.class</exclude>

 <exclude>*Suite*Test</exclude>