首页 > 其他分享 >Junit5 单元测试

Junit5 单元测试

时间:2023-06-25 10:34:02浏览次数:35  
标签:void 单元测试 public allure 测试 org Junit5 junit

一、Junit5的架构

JUnit 5由三个不同子项目中的几个不同模块组成。JUnit 5 = JUnit Platform + JUnit Jupiter + JUnit Vintage,如下:

  • JUnit platform:为了能够启动 junit 测试,IDE、构建工具或者插件需要包含和扩展平台 API。它定义了用于开发在平台上运行的新测试框架的“TestEngine”API。它还提供了一个控制台启动器来从命令行启动平台并为 Gradle 和 Maven 构建插件。
  • JUnit Jupiter:它包括用于编写测试的新编程和扩展模型。它具有所有新的 junit 注释和 TestEngine实现来运行使用这些注释编写的测试。
  • JUnit Vintage:它的主要目的是支持在 JUnit 5 平台上运行 JUnit 3 和 JUnit 4 书面测试。它有向后兼容性。

参考网站如下:

官网地址:https://junit.org/junit5/
官方入门文档:https://junit.org/junit5/docs/current/user-guide/#overview
官方例子:https://github.com/junit-team/junit5-samples
官方github:https://github.com/junit-team

二、安装

可以在 maven 或者 gradle 项目中使用 JUnit 5,下面展示在Maven中使用:

<dependencies>
        <!--配置和加载测试计划的公共API – 典型的使用场景是IDE和构建工具-->
        <dependency>
            <groupId>org.junit.platform</groupId>
            <artifactId>junit-platform-launcher</artifactId>
            <version>1.7.0</version>
            <scope>test</scope>
        </dependency>

        <!--JUnit Jupiter测试引擎的实现,仅仅在运行时需要。-->
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-engine</artifactId>
            <version>5.7.0</version>
            <scope>test</scope>
        </dependency>

        <!--JUnit Vintage测试引擎实现,允许在新的JUnit Platform上运行低版本的JUnit测试,即那些以JUnit 3或JUnit 4风格编写的测试。
        非必须
        -->
        <dependency>
            <groupId>org.junit.vintage</groupId>
            <artifactId>junit-vintage-engine</artifactId>
            <version>5.7.0</version>
            <scope>test</scope>
        </dependency>
        <!--编写测试 和 扩展 的JUnit Jupiter API。-->
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-api</artifactId>
            <version>5.7.0</version>
        </dependency>

    </dependencies>

三、JUnit 5 注释

JUnit 5 提供以下注释来编写测试:

Annotation

描述

@BeforeEach

带注释的方法将在测试类中的每个测试方法之前运行。

@AfterEach

带注释的方法将在测试类中的每个测试方法之后运行。

@BeforeAll

带注释的方法将在测试类中的所有测试方法之前运行。这个方法必须是静态的。

@AfterAll

带注释的方法将在测试类中的所有测试方法之后运行。这个方法必须是静态的。

@Test

它用于将方法标记为junit测试

@DisplayName

用于为测试类或者测试方法提供任何自定义显示名称

@Disable

它用于禁用或者忽略测试套件中的测试类或者方法。

@Nested

用于创建嵌套测试类

@Tag

用标签标记测试方法或者测试类以进行测试发现和过滤

@TestFactory

标记方法是动态测试的测试工厂

@ParameterizedTest

表示方法是参数化测试

@RepeatedTest

 表示方法是重复测试模板

@ExtendWith

用于注册自定义扩展,该注解可以继承

@FixMethodOrder(MethodSorters.NAME_ASCENDING)

控制测试类中方法执行的顺序,这种测试方式将按方法名称的进行排序,由于是按字符的字典顺序,所以以这种方式指定执行顺序会始终保持一致;不过这种方式需要对测试方法有一定的命名规则,如 测试方法均以testNNN开头(NNN表示测试方法序列号 001-999)

四、案例演示

4.1.测试:Hello World

创建Maven项目,导入Junit5依赖后,创建包 com.easybuy.method,在下面创建 类  Calculator(模拟我们需要测试的功能):

public class Calculator {

    public int add(int num1, int num2){
        return num1+num2;
    }

    public int sub(int num1, int num2){
        return num1-num2;
    }
}

创建com.easybuy.test包,在下面编写测试用例,创建 HelloWorld,代码如下:

public class HelloWorld {
    @Test
    public void testSub(){
        Calculator calculator = new Calculator();
        //调用减法
        int num = calculator.sub(10, 12);
        //分别传入预期结果和实际结果
        Assertions.assertEquals(-12,num);
    }

    @Test
    public void testAdd(){
        Calculator calculator = new Calculator();
        //调用减法
        int num = calculator.add(10, 12);
        //分别传入预期结果和实际结果
        Assertions.assertEquals(22,num);
    }
}

点击 类名或者方法名左边的按钮即可执行用例如下:

Junit5 单元测试_测试类

@Test注解在方法上标记方法为测试方法,以便构建工具和 IDE 能够识别并执行它们。

注意的用例在idea中执行的时候一直报错缺少:org.junit.jupiter.api,这个问题很奇怪,需要再idea中勾选如下配置,其他的项目不用勾选

Junit5 单元测试_Test_02

4.2.给用例添加上前置和后置

添加上前置和后置后,完成的案例代码如下:

public class AppTest {
    @BeforeAll
    static void setup(){
        System.out.println("@BeforeAll 将在测试类中的所有测试方法之前运行。这个方法必须是静态的");
    }

    @BeforeEach
    void setupThis(){
        System.out.println("@BeforeEach 将在测试类中的每个测试方法之前运行");
    }


    @Test
    public void testSub(){
        Calculator calculator = new Calculator();
        //调用减法
        int num = calculator.sub(10, 12);
        //分别传入预期结果和实际结果
        Assertions.assertEquals(-2,num);
        System.out.println("我是testSub");
    }

    @Test
    public void testAdd(){
        Calculator calculator = new Calculator();
        //调用减法
        int num = calculator.add(10, 12);
        //分别传入预期结果和实际结果
        Assertions.assertEquals(22,num);
        System.out.println("我是testAdd");
    }

    @AfterEach
    void tearThis(){
        System.out.println("@AfterEach 将在测试类中的每个测试方法之后运行。");
    }

    @AfterAll
    static void tear(){
        System.out.println("@AfterAll 将在测试类中的所有测试方法之后运行。这个方法必须是静态的");
    }
}

执行后结果如:

Junit5 单元测试_测试类_03

4.3.禁用执行某条用例

@Disabled注解可以添加给某个用例方法,或者类上,添加后面该类或者该方法不会在执行

Junit5 单元测试_测试方法_04

五、断言测试

断言有助于使用测试用例的实际输出来验证预期输出。为了简单起见,所有 JUnit Jupiter 断言都是 org.junit.jupiter.Assertions 类中的静态方法,例如

  • assertEquals 断言预期值和实际值相等
  • assertNotEquals 断言预期值和实际值不相等,则测试通过
  • assertAll 分组断言,执行其中包含的所有断言
  • assertArrayEquals 断言预期数组和实际数组相等
  • assertFalse 断言条件为假
  • assertNotNull 断言不为空
  • assertSame 断言两个对象相等
  • assertTimeout 断言超时
  • fail 使单元测试失败

案例代码如下:

public class AssertionsTest {

    @Test
    public void test1(){
        //Test will pass
        Assertions.assertEquals(3,3);
    }

    @Test
    public void test2(){
        //Test will fail
        Assertions.assertEquals(4, 4);
    }

    @Test
    public void test3(){
        int[] ints1 = new int[1024];
        int[] ints2 = new int[1024];

        //Test will fail 断言预期数组和实际数组相等
        Assertions.assertArrayEquals(ints1,ints2);
    }


    @Test
    public void test4(){
        ArrayList<String> strings = new ArrayList<>();
        strings.add("李明月");
        strings.add("刘明月");
        strings.add("张如月");

        //Test will fail 断言预期集合中是否包含某个值
        Assertions.assertTrue(strings.contains("张如月"));
    }
}

六、参数化测试

6.1.引入参数化所需依赖

实现参数化需要将下面的依赖引入到pom.xml,注意版本要和之前引入的Junit版本保持一致

dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-params</artifactId>
            <version>5.7.0</version>
            <scope>compile</scope>
        </dependency>

6.2.使用注解ParameterizedTest

使用@ParameterizedTest注解来代替@Test注解,单参数化注解使用@ValueSource ,多参数注解 @CsvSource,如果这两个注解@ParameterizedTest@Test同时使用则会多执行一次

  • 单个参数如下:
public class ParamsTest {
    //@ParameterizedTest注解来代替@Test注解,单参数化注解使用@ValueSource
    @ParameterizedTest
    @ValueSource(strings = {"张三", "小明", "小红"})//几个参数,就执行几次
    void testParamString(String name){
        System.out.println(name);
    }


    @ParameterizedTest
    @ValueSource(ints = {10,20,30})
    void testParamInt(int num){
        Assertions.assertTrue(num < 100);
        System.out.println(num);
    }
}
  • 多参数时,默认参数之间用英文逗号隔开
public class ParamsTest {
    //@ParameterizedTest注解来代替@Test注解,单参数化注解使用@ValueSource
    @ParameterizedTest
    @ValueSource(strings = {"张三", "小明", "小红"})//几个参数,就执行几次
    void testParamString(String name){
        System.out.println(name);
    }


    @ParameterizedTest
    @ValueSource(ints = {10,20,30})
    void testParamInt(int num){
        Assertions.assertTrue(num < 100);
        System.out.println(num);
    }

    //多参数
    @ParameterizedTest
    @CsvSource({"小明,10,一班","小李,11,二班"})//多参数使用@CsvSource注解实现,这里传入了两组数据,分别传入中间使用逗号隔开
    public void MultParams(String name,int age,String className ){
        System.out.println("name:"+name+" age:"+age+" classname:"+className);
    }

}
  • 参数文件:参数可以从指定csv文件中读取,在resources目录下创建csv文件,参数之间用相同分隔符分割,例如 “,”,"|"等。此时使用的注解为 @CsvFileSource

下面例如创建一个csv文件如data.csv,需要注意如果csv文件中有中文,需要通过记事本打开csv文件修改编码方式为utf-8,否则读取进来后中文会乱码,数据创建多列直接使用逗号隔开,存放在resource目录下:

Junit5 单元测试_测试方法_05

在代码中读取csv文件中的数据作为参数化的信息如下:

public class ParamsTest {
    //@ParameterizedTest注解来代替@Test注解,单参数化注解使用@ValueSource
    @ParameterizedTest
    @ValueSource(strings = {"张三", "小明", "小红"})//几个参数,就执行几次
    void testParamString(String name){
        System.out.println(name);
    }


    @ParameterizedTest
    @ValueSource(ints = {10,20,30})
    void testParamInt(int num){
        Assertions.assertTrue(num < 100);
        System.out.println(num);
    }

    //多参数
    @ParameterizedTest
    @CsvSource({"小明,10,一班","小李,11,二班"})//多参数使用@CsvSource注解实现,这里传入了两组数据,分别传入中间使用逗号隔开
    public void MultParams(String name,int age,String className ){
        System.out.println("name:"+name+" age:"+age+" classname:"+className);
    }

    @ParameterizedTest
    @CsvFileSource(resources = "/data.csv")//读取csv文件中的信息
    public void ParamByFile(String name, String password) {
        System.out.println("name:" + name + " password:" + password);
    }
}

执行后效果如下:

Junit5 单元测试_Test_06

七、测试套件

使用 JUnit 5 测试套件,我们可以运行分布到多个测试类和不同包中的测试。JUnit 5 提供了两个注解:@SelectPackages 和@SelectClasses 来创建测试套件。要执行该套件,我们将使用 @RunWith(JUnitPlatform.class)。需要引入依赖如下:

<!--创建测试套件-->
        <dependency>
            <groupId>org.junit.platform</groupId>
            <artifactId>junit-platform-suite-api</artifactId>
            <version>1.6.3</version>
        </dependency>
        <!--执行测试套件-->
        <dependency>
            <groupId>org.junit.platform</groupId>
            <artifactId>junit-platform-runner</artifactId>
            <version>1.6.3</version>
        </dependency>
  • 执行某个包下面的所有测试用例如下:
@RunWith(JUnitPlatform.class)
@SelectPackages("com.easybuy.test")//加载执行包com.easybuy.test下的所有测试用例
public class JUnit5TestSuiteExample {

}
  • 指定执行某个类下的用例
@RunWith(JUnitPlatform.class)
@SelectClasses({
        com.easybuy.test.ParamsTest.class,
        com.easybuy.test.AppTest.class
})//在测试套件中加载执行ParamsTest和AppTest类
public class JUnit5TestClassSuiteExample {
}

此外,我们可以使用以下注释来过滤测试包、类甚至测试方法。

  • @IncludePackages和 @ExcludePackages过滤包
  • @IncludeClassNamePatterns和 @ExcludeClassNamePatterns来过滤测试类
  • @IncludeTags和 @ExcludeTags来过滤测试方法
@RunWith(JUnitPlatform.class)
@SelectPackages("com.easybuy.test")//加载执行包com.easybuy.test下的所有测试用例
@ExcludeClassNamePatterns("com.easybuy.test.ParamsTest")//排除ParamsTest类
public class JUnit5TestSuiteExample {

}

执行结果如下图:

Junit5 单元测试_测试方法_07

八、Junit5结合allure生成测试报告

8.1.下载和安装allrue

由于Junit的测试结果展示过于简陋,可以借助于allure生成可视化的测试报告更加的美观同时易用性也不错,allure是一个通用的测试报告框架,

GitHub下载地址:https://github.com/allure-framework/allure2/releases,进入后选择版本下载即可:

Junit5 单元测试_测试类_08

 需要java8+,JDK 1.8+环境,所以提前配置好java环境,将安装包解压后配置allure环境变量,在系统变量path中添加到bin,例如:

D:\allure-2.21.0\bin

配置成功后在命令窗口输入allure或者allure --version,可以看到我的allure版本是2.21.0

Junit5 单元测试_Test_09

8.2.allure集成Junit5依赖导入

在pom.xml中添加依赖,然后进行配置:

<properties>
        <aspectj.version>1.9.5</aspectj.version>
        <allure.version>2.13.2</allure.version>
    </properties>

    <dependencies>
        <!--配置和加载测试计划的公共API – 典型的使用场景是IDE和构建工具-->
        <dependency>
            <groupId>org.junit.platform</groupId>
            <artifactId>junit-platform-launcher</artifactId>
            <version>1.7.0</version>
            <scope>test</scope>
        </dependency>

        <!--JUnit Jupiter测试引擎的实现,仅仅在运行时需要。-->
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-engine</artifactId>
            <version>5.7.0</version>
            <scope>test</scope>
        </dependency>

        <!--JUnit Vintage测试引擎实现,允许在新的JUnit Platform上运行低版本的JUnit测试,即那些以JUnit 3或JUnit 4风格编写的测试。
        非必须
        -->
        <dependency>
            <groupId>org.junit.vintage</groupId>
            <artifactId>junit-vintage-engine</artifactId>
            <version>5.7.0</version>
            <scope>test</scope>
        </dependency>
        <!--编写测试 和 扩展 的JUnit Jupiter API。-->
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-api</artifactId>
            <version>5.7.0</version>
        </dependency>

        <!--参数化-->
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-params</artifactId>
            <version>5.7.0</version>
            <scope>compile</scope>
        </dependency>

        <!--创建测试套件-->
        <dependency>
            <groupId>org.junit.platform</groupId>
            <artifactId>junit-platform-suite-api</artifactId>
            <version>1.6.3</version>
        </dependency>
        <!--执行测试套件-->
        <dependency>
            <groupId>org.junit.platform</groupId>
            <artifactId>junit-platform-runner</artifactId>
            <version>1.6.3</version>
        </dependency>

        <!--SL4J 主要是为了给Java日志访问提供一个标准、规范的API框架,其主要意义在于提供接口,具体的实现可以交由其他日志框架
        我的用例执行的时候console中一直提示缺少,故而添加
        -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-nop</artifactId>
            <version>1.7.2</version>
        </dependency>

        <!--Junit5集成allure-->
        <dependency>
            <groupId>io.qameta.allure</groupId>
            <artifactId>allure-junit5</artifactId>
            <version>2.13.2</version>
        </dependency>

    </dependencies>

    <!--junit allure maven运行测试用例jar包-->
    <build>
        <plugins>
            <!--junit allure maven运行测试用例jar包-->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>2.22.2</version>
                <configuration>
                    <argLine>
                        -javaagent:"${settings.localRepository}/org/aspectj/aspectjweaver/${aspectj.version}/aspectjweaver-${aspectj.version}.jar"
                    </argLine>
                </configuration>
                <dependencies>
                    <dependency>
                        <groupId>org.aspectj</groupId>
                        <artifactId>aspectjweaver</artifactId>
                        <version>${aspectj.version}</version>
                    </dependency>
                </dependencies>
            </plugin>
            <plugin>
                <groupId>io.qameta.allure</groupId>
                <artifactId>allure-maven</artifactId>
                <version>2.10.0</version>
                <configuration>
                    <reportVersion>${allure.version}</reportVersion>
                    <allureDownloadUrl>/maven2/io/qameta/allure/allure-commandline/${allure.version}/allure-commandline-${allure.version}.zip</allureDownloadUrl>
                </configuration>
            </plugin>
        </plugins>
    </build>

上面会设置后。执行用例(可以根据测试套件执行,也可以执行某个模块还是跟之前一样)生成的结果以josn格式存放在allure-results在根目录下:

Junit5 单元测试_Test_10

8.3.生成allure测试报告

8.3.1.生成在线的测试报告

生成在线版本的测试报告,在命令行打开执行即可

allure serve allure-results

如下图:

Junit5 单元测试_Test_11

8.3.1.生成文件持久型测试报告

先使用 allure generate 生成htl格式的测试结果报告

allure generate ./allure-results -o ./fileresult --clean

注意:上面的命令将 ./allure-results 目录下的测试数据生成html测试报告到 ./fileresult 路径下。–clean 先清空测试报告目录,再生成新的测试报告。

打开测试报告:

allure open -h 127.0.0.1 -p 8885 ./fileresult

启动一个web服务,将已经生成的html测试报告在默认的浏览器中打开,地址为:http://localhost:8885/

Junit5 单元测试_测试类_12

在浏览器打开测试报告如下:

Junit5 单元测试_Test_13



标签:void,单元测试,public,allure,测试,org,Junit5,junit
From: https://blog.51cto.com/u_13661275/6543933

相关文章

  • JUnit4单元测试介绍
     什么是JUnit?JUnit是测试框架,它用于Java代码的单元测试。JUnit=Java+UnitTesting什么是JUnit4?JUnit4是一个Java语言的单元测试框架,用于编写和执行单元测试。它是JUnit框架的第四个主要版本,并且是过去几年中最常用的版本。以下是一些关键特性和概念:注解驱动:J......
  • RTOS任务进行单元测试的4种策略
    https://www.beningo.com/4-tactics-to-unit-test-rtos-tasks/超过50%的嵌入式软件项目使用实时操作系统(RTOS)。不幸的是,使用RTOS会给使用现代开发技术(如测试驱动开发(TDD)、DevOps或自动测试)的开发者带来一些问题。例如,当开发者试图为他们的任务编写测试时,他们遇到的第一个问题是任......
  • mockito5.4.0单元测试(8) --验证某个方法从未被调用
    mockito官方文档地址:https://www.javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/Mockito.html#30  //usingmocks-onlymockOneisinteractedmockOne.add("one");//ordinaryverificationverify(mockOne).add("one"); //验证调用过addon......
  • mockito5.4.0单元测试(5) --校验mock对象的某种方法的准确调用次数
     mokito官方文档地址:https://www.javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/Mockito.html#exact_verification//mock一个对象LinkedListmockedList=mock(LinkedList.class);//使用mock对象来操作mockedList.add("once");//添加"once"一次......
  • mockito5.4.0单元测试(4) --主动throw异常,模拟异常处理
    importstaticorg.mockito.Mockito.*;  //引入类  LinkedListmockedList=mock(LinkedList.class);  //获得mock对象 //stubbingwhen(mockedList.get(0)).thenReturn("first");     //如果获取0索引,则返回:first when(mockedList.get(1)).the......
  • mockito5.4.0单元测试(1) 官方文档地址
    mockito官方文档地址:https://www.javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/Mockito.html  end.......
  • 单元测试-在弹簧测试上禁用@EnableScheduling
    当我运行单元测试时,它会调用我的计划任务。我想防止这种行为,这是由于我的主应用程序配置中包含@EnableScheduling而引起的。如何在单元测试中禁用此功能?我遇到了这个建议设置个人资料的问题/答案。不知道我该怎么做?还是过度杀伤力?我当时在考虑为我的单元测试使用一个单独的Ap......
  • spring6整合JUnit5
    1. Spring对JUnit4的支持   136准备工作:pom.xml<?xmlversion="1.0"encoding="UTF-8"?><projectxmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:sch......
  • 【gtest】Visual Studio 2019 单元测试学习Google Test
    前言记录在VS2019中使用自带的GoogleTest进行单元测试的方法和经验项目介绍总共2个项目,Work为项目工程,TestWork为Work工程的单元测试工程,TestWork依赖于Work工程,但是Work不依赖TestWork,TestWork是Work的旁路辅助工程,用于对代码的检查和测试。创建项目创建C++的常规Work工程......
  • iOS 单元测试之常用框架 OCMock 详解
    一、单元测试1.1单元测试的必要性测试驱动开发并不是一个很新鲜的概念了。在日常开发中,很多时候需要测试,但是这种输出是必须在点击一系列按钮之后才能在屏幕上显示出来的东西。测试的时候,往往是用模拟器一次一次的从头开始启动app,然后定位到自己所在模块的程序,做一系列的点击......