首页 > 编程语言 >Java Junit5 使用小结

Java Junit5 使用小结

时间:2023-11-21 17:44:23浏览次数:36  
标签:Java void junit jupiter Assertions 测试 Junit5 小结 public

在我们的日常开发中,代码一边编码一边自测是常有的事,做好单元测试也是一名开发应该掌握的技能,不说测试搞得多么强,至少会基本的,会功能测试,会性能测试。今天来学习下 单元测试。

1.JUnit5介绍

现在主要版本是 JUnit5,所以后面的内容也都是基于 JUnit5 做相关的介绍。JUnit5 是 JUnit 单元测试框架的重大升级,需要运行在 Java8 以上的环境。

JUnit5可以理解为是由三个不同而子项目构成:

  • 1.JUnit Platform,用于JVM上启动测试框架的基础服务,提供命令行,IDE和构建工具等方式执行测试的支持。
  • 2.JUnit Jupiter,包含 JUnit 5 新的编程模型和扩展模型,主要就是用于编写测试代码和扩展代码。
  • 3.JUnit Vintage,用于在JUnit 5 中兼容运行 JUnit3.x 和 JUnit4.x 的测试用例。

JUnit5目前的主要特性:

  • 提供全新的断言和测试注解,支持测试类内嵌
  • 更丰富的测试方式:支持动态测试,重复测试,参数化测试等
  • 实现了模块化,让测试执行和测试发现等不同模块解耦,减少依赖
  • 提供对 Java 8 的支持,如 Lambda 表达式,Sream API等。

2.测试环境

  • Java 21
  • Junit 5.10.0

3.Maven依赖

本篇学习内容涉及的依赖如下:

    <!-- 基础测试 -->
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter-api</artifactId>
        <version>5.10.0</version>
    </dependency>
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter-engine</artifactId>
        <version>5.10.0</version>
    </dependency>

    <!-- 带参测试 -->
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter-params</artifactId>
        <version>5.10.0</version>
    </dependency>

4.典型注解

@BeforeAll

修饰 static 方法,定义整个测试类在开始前的操作,比如一些初始化的操作。

@AfterAll

修饰 static 方法,定义整个测试类在结束时的操作,比如一些清理工作。

@BeforeEach && @AfterEach

标注在每个测试用例方法,表示方法开始前或结束时的执行,负责该测试用例所需要的的运行环境的准备和销毁。

@Test

表示这个测试方法是一个测试用例。

由上面的这些注解,我们可以做出如下流程来表示单元测试的完整过程:
image.png

@DisplayName

可以加在类上,也可以加在测试方法上,相当于一个显示名。

@Disable

相当于禁用当前的测试方法,测试时就会忽略该方法。

@RepeatedTest

表示该方法需要重复运行,具体几次,可以通过参数传入。

基于上面的介绍,我们写一个简单的类测试:

package org.example;

import org.junit.jupiter.api.*;

import java.time.Duration;

@DisplayName("我的第一个测试用例")
public class MyFirstTestCaseTest {
    @BeforeAll
    public static void init() {
        System.out.println("初始化数据");
    }

    @AfterAll
    public static void cleanup() {
        System.out.println("清理数据");
    }

    @BeforeEach
    public void tearUp() {
        System.out.println("当前测试方法开始");
    }

    @AfterEach
    public void tearDown() {
        System.out.println("当前测试方法结束");
    }

    @DisplayName("我的第一个测试")
    @Test
    public void testFirstTest() {
        System.out.println("我的第一个测试开始");
    }

    @DisplayName("我的第二个测试")
    @Test
    public void testSecondTest() {
        System.out.println("我的第二个测试开始");
    }

    @DisplayName("我的第三个测试")
    @Disabled
    @Test
    public void testThirdTest() {
        System.out.println("我的第三个测试开始测试");
    }

    @DisplayName("我的第四个测试-重复测试")
    @RepeatedTest(value = 3, name = "{displayName} 第 {currentRepetition} 次")
    public void repeatedTest() {
        System.out.println("正在执行重复测试");
    }
}    

5.断言

在测试方法中,我们常常是给定一个预期的值和测试的结果值作比较,看对应的结果怎样,由此就由相关断言:

  • 断言相等,assertEqual
  • 断言不等,assertNotEqual
  • 多个断言,assertAll
  • 断言空或非空,assertNull/assertNotNull
  • 断言 true或false,assertTrue/assertFalse
  • 超时断言,assertTimeout/assertTimeoutPreemptively
  • 断言实例,assertInstanceOf
  • 断言异常,assertThrows

由于断言类包含内容很多,每个方法实际很多重载,这里仅挑选几个重点说说,其他都是类似的。

demo

@DisplayName("我的第五个测试-单个断言")
@Test
public void testSingleAssertion() {
    Integer num = 1;
    Assertions.assertEquals(num, 1);
}

@DisplayName("我的第六个测试-多断言")
@Test
public void testGroupAssertions() {
    int[] nums = {0, 1, 2, 3, 4};
    Assertions.assertAll("nums",
            () -> Assertions.assertEquals(nums[0], 0),
            () -> Assertions.assertEquals(nums[1], 1),
            () -> Assertions.assertEquals(nums[2], 2),
            () -> Assertions.assertEquals(nums[3], 3),
            () -> Assertions.assertEquals(nums[4], 4)
        );
}

@DisplayName("我的第七个测试-超时操作")
@Test
public void testShouldCompleteInOneSecond() {
    // 无法做到时间的精确匹配
    Assertions.assertTimeoutPreemptively(Duration.ofSeconds(1), () -> Thread.sleep(999));
}

@DisplayName("我的第八个测试-异常测试")
@Test
public void testAssertThrowsException() {
    String str = null;
    // str 作为传入参数,会报非法传参异常,所以可以正常断言到
    Assertions.assertThrows(IllegalArgumentException.class, () -> {
        Integer.valueOf(str);
    });
}

6.带参数的测试方法

有的时候我们需要一些带参数的测试方法,比如一次测试一个参数不够,那就来一组参数,或者有的传参需要多个参数怎么办。

这里我们用到了 Junit5的 params 包提供功能,这也是上面我们在依赖中添加的依赖项。

在有带参数的单元测试中主要介绍几个常用的,其他感兴趣可以看看源码。

@ParameterizedTest

此处可以用来代替 @Test 注解,一样的功效。

@ValueSource

指定我们的传入的这一组参数,可以是:

  • ints
  • strings
  • classes等

包含类型覆盖基本类型。

@CsvSource

规定了传入的多个入参的组合形式,默认用“,”分隔。

下面是个简单的 demo:

package org.example;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import org.junit.jupiter.params.provider.ValueSource;

public class ParameterUnitTest {
    @ParameterizedTest
    @ValueSource(ints = {2, 4, 8, 10})
    public void testIsEvenNumber(int num) {
        Assertions.assertEquals(0, num % 2);
    }

    @ParameterizedTest
    @ValueSource(strings = {"Effective Java", "C Plus Plus"})
    public void testPrintTitle(String title) {
        System.out.println(title);
    }

    // 多参数
    @ParameterizedTest
    @CsvSource({"1,One", "2,Two"})
    public void testDataFromCSV(long id, String name) {
        System.out.printf("id: %d, name: %s\n", id, name);
    }
}

以上这些都是一些基本用法,有的时候我们需要依赖其他类,所以就会有 mock打桩 的需求,这是后话了,掌握这些基本用法能覆盖相当的开发自测了。

参考:

标签:Java,void,junit,jupiter,Assertions,测试,Junit5,小结,public
From: https://www.cnblogs.com/davis12/p/17847175.html

相关文章

  • JAVA树形结构查询
    1. 2. setDeep查询几层,不固定默认查询全部层 ......
  • 【JAVA基础】事务管理
    @Transactional注解的属性介绍@Transactional(propagation=Propagation.REQUIRED,rollbackFor=Exception.class)......
  • JavaWeb01-JDBC学习总结
    为什么需要JDBC?JDBC就是使用Java语言来操作关系型数据库的一套API。市场拥有众多的数据库:MySQL、Oracle、DB2等等。不可能每个数据库都重新开发Java代码来适配不同的数据库,那么Sun公司定义一套标准接口来统一操作数据库。其中所谓的MySQL实现类就是MySQL驱动(驱动Jar包)这样就只需要......
  • JAVA SERVLET踩坑技术
    今天给大家分享一下踩坑记录。今天准备用Servlet重新开发一个web程序。开始是通过实现Servlet今天实现的。@WebServlet("/demo1")publicclassServletDemo1implementsServlet{publicvoidinit(ServletConfigservletConfig)throwsServletException{System.o......
  • Java基础
    Java枚举EnumJava枚举是一个特殊的类,一般表示一组常量Java枚举类使用enum关键字来定义,各个常量使用逗号,来分割。示例enumAnimal{CAT,DOG,BIRD;}publicclassEnumTest{publicvoiddemo(){Animalanimal=Animal.DOG;System.out......
  • JAVA Tips (记录一些常用,容易混乱的小知识)
    记录一些常用,容易混乱的小知识1、Json(JsonNode)判断对应的JsonNode中的数据......
  • Java单列集合Set:HashSet与LinkedHashSet详解,为什么它比List接口更严格?
    上篇我们介绍了单列集合中常用的list接口,本篇我们来聊聊单列集合中的另外一个重要接口Set集合。1、Set介绍java.util.Set接口和java.util.List接口一样,同样实现了Collection接口,它与Collection接口中的方法基本一致,并没有对Collection接口进行功能上的扩充,只是比Collection接口......
  • 数据结构之二叉树的遍历3(java)
    一:概述绝大多数的可以用递归解决问题,也可以使用另一种数据结构来解决,这种数据结构就是栈。因为递归和栈都有回溯的特性。二:具体说明如何借助栈来实现二叉树的遍历,下面以二叉树的前序遍历为例,来阐述具体过程。<1>首先遍历二叉树的根节点1,放入栈中。<2>遍历根节点1的左孩子节点2,放入......
  • Linux部署Java环境
    本文使用的Linux发行版本为AlmaLinux9.264位(CentOS停止更新后的完美替代发行版本)。本文安装的JDK版本为21.0.1,其他版本方法类似。下载并安装Java开发工具包(JavaDevelopmentKit)更新系统。dnf-yupdate获取安装包链接。前往JDK下载官网。找到对应Linux版本的压缩......
  • java finally一定会执行吗?
    1.答案是不一定,而且很容易弄出不执行的情况;最简单的:在IDEA上执行:try{log("aaa");Thread.sleep(10000);log("bbbb");}catch(Exceptione){log("ddd");}finally{log("eee");}在打印了aaa后点击红色方框停止按钮,会发现应用就停止了,然后没有继续打......