Junit5基础教程

Junit5的构成:

  • Junit Platform+Junit Jupiter+Junit Vintage
  • Junit Platform:是Junit向测试平台演进,提供平台功能的模块,通过这个其他的自动化引擎可以接入Junit,实现对接和执行
  • Junit Jupiter:核心,承载Juint4原有功能+丰富的新特性
  • Junit Vintage:主要功能是对Juint旧版本进行兼容

一,导入依赖

 <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <junit-platform.version>1.8.1</junit-platform.version>
        <junit-jupiter.version>5.8.1</junit-jupiter.version>
    </properties>
    <build>
        <pluginManagement>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-surefire-plugin</artifactId>
                    <version>3.0.0-M5</version>
                    <dependencies>
                        <dependency>
                            <groupId>org.junit.jupiter</groupId>
                            <artifactId>junit-jupiter-engine</artifactId>
                            <version>5.8.1</version>
                        </dependency>
                    </dependencies>
                    <configuration>
                        <includes>
                            <include>**/*Test.java</include>
                        </includes>
                    </configuration>
                </plugin>

                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>3.8.1</version>
                    <configuration>
                        <source>1.8</source>
                        <target>1.8</target>
                    </configuration>
                </plugin>
            </plugins>
        </pluginManagement>
    </build>
  <!--核心依赖-->
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-engine</artifactId>
            <version>5.8.1</version>
        </dependency>
        <!--套件测试使用-->
        <dependency>
            <groupId>org.junit.platform</groupId>
            <artifactId>junit-platform-runner</artifactId>
            <version>1.8.1</version>
        </dependency>
        <dependency>
            <groupId>org.junit.platform</groupId>
            <artifactId>junit-platform-runner</artifactId>
            <version>1.8.1</version>
        </dependency>

二,基本功能

一、常用断言

在这里插入图片描述

二、执行顺序和常用注解

1、通过BeforeAll类的注解来保证顺序
// 执行顺序:beforeAll-beforeEach-afterEach-afterAll
@DisplayName("常用注解测试")
public class TestCase {
    /**
     * @BeforeAll和@AfterAll 必须静态修饰,在所有方法执行前后只执行一次
     * @Test 一个方法
     * @AfterEach和@BeforeEach 每次方法执行前都会执行一次
     * @DisplayName() 类似注解的功能
     * @RepeatedTest(5) 重复5次
     * @Disabled 不执行该方法
     * @Tags 打标签
     */
    @BeforeAll
    public static void beforeAll() {
        System.out.println("BeforeAll再每个类中只执行一次,且是在开头执行");
    }

    @BeforeEach
    public void beforeEach() {
        System.out.println("BeforeEach在每个方法执行前都会执行一次");
    }

    // junit5不需要访问修饰符
    //  @Disabled表示不执行
    @Test
    @Disabled
    @DisplayName("方法1")
    void fun1() {
        System.out.println("---fun1---");
    }

    @Test
    @DisplayName("方法2")
    @RepeatedTest(5)
    void fun2() {
        System.out.println("---fun2---");
    }

    @Test
    @Tag("tag1")
    void tagTest(){
        System.out.println("tag1");
    }
    @AfterEach
    public void afterEach() {
        System.out.println("AfterEach在每个方法执行前都会执行一次");
    }

    @AfterAll
    public static void afterAll() {
        System.out.println("afterAll再每个类中只执行一次,且是在结尾执行");
    }
}

2、通过order注解来保证执行顺序
import org.junit.jupiter.api.MethodOrderer.OrderAnnotation;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;
 
@TestMethodOrder(OrderAnnotation.class)
class OrderedTestsDemo {
 
  @Test
  @Order(1)
  void nullValues() {
      // perform assertions against null values
  }
 
  @Test
  @Order(2)
  void emptyValues() {
      // perform assertions against empty values
  }
 
  @Test
  @Order(3)
  void validValues() {
      // perform assertions against valid values
  }
}
  • allure注解
    在这里插入图片描述

三、依赖测试

/**
 * @Nested:
 * 功能类似于suite测试套件
 * 从下往上执行
 */

public class NestedTest {
    private static HashMap<String, Object> dataMap = new HashMap<String, Object>();

    @Test
    void login() {
        dataMap.put("login", "登录成功");
    }

    @Nested
    class Shopping{
        @Test
        void shopping(){
            if (null!=dataMap.get("buy")){
                System.out.println("购买成功啦!");
            }else {
                System.out.println("购买失败");
            }
        }
    }

    @Nested
    class Buy {
        @Test
        void buyTest() {
            if (dataMap.get("login").equals("登录成功")) {
                System.out.println("登录成功");
                dataMap.put("buy", "登录成功,快去购物吧!");
            } else {
                System.out.println("登录失败");
            }
        }
    }
}

四、参数化测试

写过一篇,点这里!!

五、测试套件

SelectPackages、IncludePackages、SelectClasses、IncludeTags等注解的使用
/**
 * SelectPackages 选择需要执行的包
 */
@RunWith(JUnitPlatform.class)
@SelectPackages({"com.testCase2"})
public class SelectPackagesTest {

}
/**
 * @IncludePackages需要和@SelectPackages搭配使用
 * @IncludePackages是在@SelectPackages的基础上再做一层筛选
 * ps:一定要注意,包下的类名一定要Test开头或者结尾,否则就不执行了!!!
 */
@RunWith(JUnitPlatform.class)
@SelectPackages({"com.testCase2"})
// 只执行com.testCase2.demo1
@IncludePackages({"com.testCase2.demo1"})
public class IncludePackagesTest {
}
/**
 * @SelectClasses和@IncludeTags组合使用,在方法里选出对应的标签
 * 还有@ExcludeTag
 */
@RunWith(JUnitPlatform.class)
@SelectClasses({TestCase.class})
//@IncludeTags("tag1")
@ExcludeTags("tag1")
public class SelectClassesTest {
}

六、软断言

  • assertAll断言方法,会在执行完所有断言后统⼀输出结果,⼀次性暴露所有问题,提高了测试脚本的健壮性。
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.function.Executable;

import java.util.ArrayList;
import java.util.List;

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

public class AssertAllDemo {
    // 普通方法,第一个执行失败以后后面都不执行
    @Test
    void assertTest1() {
        Assertions.assertTrue(2 == 1);
    }

    void assertTest2() {
        Assertions.assertTrue(3 == 1);
    }

    void assertTest3() {
        Assertions.assertTrue(1 == 1);
    }

    // 用了assertAll之后,所有方法都执行
    @Test
    void assertAllTest() {
        assertAll(
                "多次结果校验",
                () -> {
                    Assertions.assertTrue(2 == 1);
                },
                () -> {
                    Assertions.assertTrue(3 == 1);
                }
        );
    }

    @Test
    void assertAllTtest02() {
        List<Executable> assertList = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            int result = i;
            System.out.println(result);
            assertList.add(() -> {
                Assertions.assertEquals(10, result);
            });
        }
        assertAll("多次结果校验", assertList.stream());
    }

}

七、并发测试

  • 测试环境基本上都是单线程操作,而线上存在分布式的并发场景,所以并不能暴露所有问题,这里就需要用到并发
  • junit测试是在⼀个线程中串行执行的,从5.3开始⽀持并行测试。⾸先需要在配置⽂件junit-platform.properties 中配置。
#是否允许并行执行true/false
junit.jupiter.execution.parallel.enabled = true
#是否支持方法级别多线程same_thread/concurrent
junit.jupiter.execution.parallel.mode.default = concurrent
#是否支持类级别多线程same_thread/concurrent
junit.jupiter.execution.parallel.mode.classes.default = concurrent
# the maximum pool size can be configured using a ParallelExecutionConfigurationStrategy
junit.jupiter.execution.parallel.config.strategy=fixed
junit.jupiter.execution.parallel.config.fixed.parallelism=4

import org.junit.jupiter.api.RepeatedTest;
import org.junit.jupiter.api.Test;

/**
 * 并发测试
 */
public class ParallelTest {
  static   int result = 0;

    // 加synchronized可以保证其原子性,但是如果是分布式系统是不适合的,需要用如redis分布式锁
    public static  int cal(int x) throws InterruptedException {
        int i = result;
        Thread.sleep(1000);
        result = i + x;
        return result;
    }
    public static int add(int x,int y) throws InterruptedException {
        Thread.sleep(1000);
        result = y + x;
        return result;
    }
    @RepeatedTest(10)
    public void testCal() throws InterruptedException {
        long id = Thread.currentThread().getId();
        System.out.println("线程" + id + "为你服务:" + cal(1));
    }
    @RepeatedTest(10)
    public void testAdd() throws InterruptedException {
        long id = Thread.currentThread().getId();
        System.out.println("加法计算:线程" + id + "为你服务:" + add(1,2));
    }
}

八、动态测试解决硬编码问题

  • 传统自动化测试思路中,我们的测试逻辑是在以硬编码的形式组织到代码里的,当遇到用例迁移或结果整合时,会产生大量的逻辑重写
  • JUnit5提供了动态测试方案,让测试人员可以在脚本Runtime时动态的批量生成用例
  • 现在我们有一个需求,要把yaml文件内容转为测试用例,解决思路如下:
    在这里插入图片描述
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.DynamicTest;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestFactory;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * 动态测试demo
 * 需求:把result.yaml脚本变成测试用例
 * 首先把它通过反序列化变成对象
 * 然后把它添加到dynamicTestList
 */
public class ShellTestResult {
        @TestFactory
    Collection<DynamicTest> shellTestResult() throws IOException {
        // 新建一个列表来存储数据(不是结果)
        List<DynamicTest> dynamicTestList = new ArrayList<>();
        ObjectMapper mapper = new ObjectMapper(new YAMLFactory());
        // 反序列化方式把yaml文件转换为对象列表
        ResultList resultList = mapper.readValue(new File("D:\\interface_auto\\src\\main\\resources\\result.yaml"), ResultList.class);
        System.out.println("done");
        // 动态遍历生成测试方法
        for (Result result : resultList.getResultList()) {
            // 把数据收集起来
            dynamicTestList.add(
                    // 动态生成测试方法
                    DynamicTest.dynamicTest(result.getCaseName(), () -> {
                        Assertions.assertTrue(result.isResult());
                    })
            );
        }
        return dynamicTestList;
    }
}

import lombok.Data;

@Data
public class Result {
    private String caseName;
    private boolean result;

    public boolean isResult() {
        return result;
    }

    public void setResult(boolean result) {
        this.result = result;
    }
}
@Data
public class ResultList {
    private List<Result> resultList;
}

九、Junit5启动类(适用于持续集成)

import org.junit.platform.launcher.Launcher;
import org.junit.platform.launcher.LauncherDiscoveryRequest;
import org.junit.platform.launcher.TestExecutionListener;
import org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder;
import org.junit.platform.launcher.core.LauncherFactory;
import org.junit.platform.launcher.listeners.SummaryGeneratingListener;

import static org.junit.platform.engine.discovery.ClassNameFilter.includeClassNamePatterns;
import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass;
import static org.junit.platform.engine.discovery.DiscoverySelectors.selectPackage;

/**
 * junit5启动类(适用于持续集成这种点不了执行的)
 */
public class LauncherDemo {
    public static void main(String[] args) {
        LauncherDiscoveryRequest request = LauncherDiscoveryRequestBuilder.request().selectors(
                // 2个过滤条件是or不是and:
                selectPackage("com.learn.junit5"),
                selectClass(TestExecutionOrder.class)
        ).filters(
//                includeClassNamePatterns("Test.*")
        )
                .build();
        Launcher launcher = LauncherFactory.create();
        TestExecutionListener listener = new SummaryGeneratingListener();
        launcher.registerTestExecutionListeners(listener);
        launcher.execute(request);
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/389892.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

苹果手机充电充不进去怎么办?这里有你想要的一些故障排除技巧

当你的iPhone插上充电器或将其放在无线充电器上充电时,稍后再检查发现它没有充电,怎么办呢?可能的原因不少。让我们来看看一些最常见的iPhone充电问题,以及你能做些什么。 常规故障排除提示 故障排除中最基本的技术之一是用已知的好的相同组件代替不起作用的组件,如把你的…

【复现】cellinx摄像设备 未授权漏洞_50

目录 一.概述 二 .漏洞影响 三.漏洞复现 1. 漏洞一&#xff1a; 四.修复建议&#xff1a; 五. 搜索语法&#xff1a; 六.免责声明 一.概述 cellinx是一家韩国的摄像设备 二 .漏洞影响 通过未授权访问可以创建用户进入后台&#xff0c;可能造成系统功能破坏。 三.漏洞复…

python工具方法 45 基于ffmpeg以面向对象多线程的方式实现实时推流

1、视频推流 参考基于ffmpeg模拟监控摄像头输出rtsp视频流并opencv播放 实现视频流的推流。 其基本操作就是,安装视频流推流服务器,ffmpeg,准备好要推流的视频。 命令如下所示:ffmpeg -re -stream_loop -1 -i 风景视频素材分享.flv -c copy -f rtsp rtsp://127.0.0.1:554/…

挑战杯 python的搜索引擎系统设计与实现

0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; python的搜索引擎系统设计与实现 &#x1f947;学长这里给一个题目综合评分(每项满分5分) 难度系数&#xff1a;3分工作量&#xff1a;5分创新点&#xff1a;3分 该项目较为新颖&#xff…

租赁香港服务器多少钱一个月?24元

阿里云香港服务器2核1G、30M带宽、40GB ESSD系统盘优惠价格24元/月&#xff0c;288元一年&#xff0c;每月流量1024GB&#xff0c;多配置可选&#xff0c;官方优惠活动入口 https://t.aliyun.com/U/bLynLC 阿里云服务器网aliyunfuwuqi.com分享阿里云香港服务器优惠活动、详细配…

图像识别基础之模板匹配

principle 图像匹配 本质&#xff1a;图像的相似度很高(矩阵的相似度很高) code /*\brief 我的图像匹配函数&#xff0c;获取差方和均值最小的矩阵作为结果\param srcPicFile:用以匹配的图像文件\param templatePicFile:模板图像文件\param destPicFile:输出的检测结果文件…

【方法】如何打开带密码的RAR分卷压缩文件?

RAR分卷文件是一种特殊的RAR压缩文件格式&#xff0c;也就是将文件压缩成多个相同大小的压缩包&#xff0c;可以更方便传输。那如果收到了带有密码的RAR分卷压缩文件&#xff0c;要如何打开呢&#xff1f; 无论RAR分卷压缩文件是否设置了密码保护&#xff0c;在打开或者解压分…

数据结构与算法:双向链表

朋友们大家好啊&#xff0c;在上节完成单链表的讲解后&#xff0c;我们本篇文章来对带头循环双向链表进行讲解 双向链表 双向链表、头节点和循环的介绍构建双向链表节点的构建初始化双向循环链表&#xff08;空链表&#xff09;销毁双向链表 链表的打印双向链表头尾的插与删尾插…

基于Java (spring-boot)的房屋租赁管理系统

一、项目介绍 基于Java (spring-boot)的房屋租赁管理系统功能&#xff1a;登录、管理员、租客、公告信息管理、房屋信息管理、用户信息管理、租金信息管理、故障信息管理、房屋出租信息详情、个人信息、修改密码、等等等。 适用人群&#xff1a;适合小白、大学生、毕业设计、课…

【C语言】指针的进阶篇,深入理解指针和数组,函数之间的关系

欢迎来CILMY23的博客喔&#xff0c;本期系列为【C语言】指针的进阶篇&#xff0c;深入理解指针和数组&#xff0c;函数之间的关系&#xff0c;图文讲解其他指针类型以及指针和数组&#xff0c;函数之间的关系&#xff0c;带大家更深刻理解指针&#xff0c;以及数组指针&#xf…

谁拿了最多奖学金——NOIP 2005 提高组

输入样例&#xff1a; 4 YaoLin 87 82 Y N 0 ChenRuiyi 88 78 N Y 1 LiXin 92 88 N N 0 ZhangQin 83 87 Y N 1 输出样例&#xff1a; ChenRuiyi 9000 28700 这道题用结构体做对吧 #include <bits/stdc.h> using namespace std; class student{public:string name;int FG…

Springboot+vue的大学生智能消费记账系统的设计与实现(有报告)。Javaee项目,springboot vue前后端分离项目

演示视频&#xff1a; Springbootvue的大学生智能消费记账系统的设计与实现&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot vue前后端分离项目 项目介绍&#xff1a; 本文设计了一个基于Springbootvue的大学生智能消费记账系统的设计与实现&#xff0c;采…

Midjourney绘图欣赏系列(三)

Midjourney介绍 Midjourney 是生成式人工智能的一个很好的例子&#xff0c;它根据文本提示创建图像。它与 Dall-E 和 Stable Diffusion 一起成为最流行的 AI 艺术创作工具之一。与竞争对手不同&#xff0c;Midjourney 是自筹资金且闭源的&#xff0c;因此确切了解其幕后内容尚不…

platformio 提示 fatal error: TimeLib.h: No such file or directory 的解决方案

在platformio编译arduino项目的时候&#xff0c;如果提示fatal error: TimeLib.h: No such file or directory&#xff0c;解决方法有2&#xff1a; 方法1&#xff1a; 在项目的platformio.ini文件中&#xff0c;添加 lib_deps # Using library Id44方法2&#xff1a; 通过…

C++ 模板进阶

C 模板进阶 一.非类型模板参数1.概念2.实例3.注意事项 二.模板的特化1.引出2.函数模板的特化1.语法和使用2.建议 3.类模板的特化1.全特化2.偏特化1.部分特化2.对参数进行进一步的限制 4.匹配顺序 三.模板的分离编译1.什么是分离编译2.模板的分离编译3.解决方法1.显式实例化(不推…

C++中的拷贝构造函数

一、拷贝构造函数的概念 拷贝构造函数用于创建一个与已有对象相同的对象&#xff0c;本质上也是构造函数的重载 拷贝构造函数只有一个类型为 const 类类型引用的形参&#xff0c;当我们要创建一个与已存在对象相同的对象时&#xff0c;由编译器自动调用拷贝构造函数。 clas…

MySQL运行错误:‘mysql‘不是内部或外部命令,也不是可运行程序或批处理文

主要原因是&#xff1a;没有将mysql安装目录下的bin目录&#xff0c;添加到系统变量中 编辑系统环境变量 双击Path即可 下一步 记得每一步点击确定就好啦。 下面验证一下是否成功呢&#xff1f; 输入命令符(V是大写的哦~&#xff09; mysql -V 以上就是成功啦&#xff01…

Flink理论—容错之状态

Flink理论—容错之状态 在 Flink 的框架中&#xff0c;进行有状态的计算是 Flink 最重要的特性之一。所谓的状态&#xff0c;其实指的是 Flink 程序的中间计算结果。Flink 支持了不同类型的状态&#xff0c;并且针对状态的持久化还提供了专门的机制和状态管理器。 Flink 使用…

一周学会Django5 Python Web开发-项目配置settings.py文件-模版配置

锋哥原创的Python Web开发 Django5视频教程&#xff1a; 2024版 Django5 Python web开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili2024版 Django5 Python web开发 视频教程(无废话版) 玩命更新中~共计17条视频&#xff0c;包括&#xff1a;2024版 Django5 Python we…

OpenAI突然发布首款文生视频模型——Sora;谷歌发布Gemini 1.5,迈向多模态大模型新时代

&#x1f989; AI新闻 &#x1f680; OpenAI突然发布首款文生视频模型——Sora 摘要&#xff1a;OpenAI发布了首个AI视频模型Sora&#xff0c;可以根据文字指令生成神级效果的长视频&#xff0c;引发了广泛关注和震惊。 Sora模型通过深入理解语言和图像&#xff0c;能够创造出…