自动化测试之JUnit单元测试框架

news2024/12/24 2:20:21

目录

一、什么是 JUnit

二、JUnit5 相关技术

1.注解

1.1 @Test

1.2 @Disabled

1.3 @BeforeAll、@AfterAll

1.4 @BeforeEach、@AfterEach

2.参数化

2.1 单参数

2.2 CSV 获取参数

2.3 方法获取参数

2.4 多参数

3.测试用例的执行顺序

3.1 顺序执行:@TestMethodOrder(MethodOrderer.OrderAnnotation.class)

3.2 随机执行:@TestMethodOrder(MethodOrderer.class)

4.断言

5.测试套件

5.1 通过 class 运行测试用例

5.2 通过包运行测试用例


🌈本节课我们来学习单元测试框架 Junit,这里的单元测试指的是对最小的软件设计单元(模块)进行验证,在UI自动化测试里面,我们的单元测试主要针对UI界面的功能进行自动化测试。

一、什么是 JUnit

JUnit是一个Java单元测试框架。它由Kent Beck和Erich Gamma建立,逐渐成为源于Kent Beck的sUnit的xUnit家族中最为成功的一个JUnit有它自己的JUnit扩展生态圈。多数Java的开发环境都已经集成了JUnit作为单元测试的工具。

注意:Junit 测试也是程序员测试,即所谓的白盒测试,它需要程序员知道被测试的代码如何完成功能,以及完成什么样的功能

它包括以下特性:

  1. 用于测试期望结果的断言(Assertion)
  2. 用于共享共同测试数据的测试工具
  3. 用于方便的组织和运行测试的测试套件
  4. 图形和文本的测试运行器

使用 Junit 能让我们快速的完成单元测试。

🌈通常我们写完代码想要测试这段代码的正确性,那么必须新建一个类,然后创建一个 main() 方法,然后编写测试代码。如果需要测试的代码很多呢?那么要么就会建很多main() 方法来测试,要么将其全部写在一个 main() 方法里面。这也会大大的增加测试的复杂度,降低程序员的测试积极性。而 Junit 能很好的解决这个问题,简化单元测试,写一点测一点,在编写以后的代码中如果发现问题可以较快的追踪到问题的原因,减小回归错误的纠错难度。

二、JUnit5 相关技术

通常我们使用 JUnit5 版本

1.注解

注解(也可以称为 元数据)为在代码中添加信息提供了一种形式化的方法,使得在代码中任一时刻可以非常方便的使用这些数据;注解类型定义了一种新的特殊接口类型,在接口关键期 interface 之前加@符号,即用@interface即可区分注解与普通接口声明。目前大部分框架都是通过使用注解简化代码提高编码效率

1.1 @Test

JUnit提供了非常强大的注解功能,通过 @Test 注解修饰到方法上,该方法就变为了一个测试方法执行当前类时,会自动的执行该类下所有带 @Test 注解的用例

使用这些JUnit提供的注解时,需要在pom.xml文件中进行配置(记得配置完要进行刷新):maven中央仓库

<!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-api -->
<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter-api</artifactId>
    <version>5.9.2</version>
    <scope>test</scope>
</dependency>

    <dependencies>
        <!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-api -->
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-api</artifactId>
            <version>5.9.2</version>
        </dependency>
    </dependencies>

在 main 文件中,我们需要导入 Test 包:

我们写一个测试用例:

import org.junit.jupiter.api.Test;
public class JUnitDemo1 {
    @Test
    void Test01() {
        System.out.println("这是 JunitDemo1 里的 Test01");
    }
    @Test
    void Test02() {
        System.out.println("这是 JunitDemo1 里的 Test02");
    }
}

❗❗需要注意的是写的代码几个运行按钮:

 其中“对号”表示测试通过;“ !”表示测试错误

1.2 @Disabled

Disabled 表示 忽略

import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
public class JUnitDemo1 {
    @Test
    void Test01() {
        System.out.println("这是 JunitDemo1 里的 Test01");
    }
    @Test
    void Test02() {
        System.out.println("这是 JunitDemo1 里的 Test02");
    }
    @Disabled
    void Test03() {
        WebDriver webDriver = new ChromeDriver();
        webDriver.get("https://www.baidu.com");
        webDriver.findElement(By.cssSelector("#kw")).sendKeys("521");
        webDriver.findElement(By.cssSelector("#su")).click();
    }
}

此时我们看到这个代码就不执行 Test03 

1.3 @BeforeAll、@AfterAll

@BeforeAll:当前的方法需要在当前类下所有用例执行之前执行一次,且被该注解修饰的方法必须为静态方法

@AfterAll:当前的方法需要在当前类下所有用例执行之后执行一次,且被该注解修饰的方法必须为静态方法

例如在 UI 自动化中:通常情况下,创建文件、打开网页放在BeforeAll 里边;关闭浏览器放在AfterAll 里边

import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;


public class JUnitDemo1 {
    @Test
    void Test01() {
        System.out.println("这是 JunitDemo1 里的 Test01");
    }
    @Test
    void Test02() {
        System.out.println("这是 JunitDemo1 里的 Test02");
    }
    @Disabled
    void Test03() {
        WebDriver webDriver = new ChromeDriver();
        webDriver.get("https://www.baidu.com");
        webDriver.findElement(By.cssSelector("#kw")).sendKeys("521");
        webDriver.findElement(By.cssSelector("#su")).click();
    }
    @BeforeAll
    static void SetUp() {
        System.out.println("这是我们 BeforeAll 里边的语句");
    }
    @AfterAll
    static void TearDown() {
        System.out.println("这是我们 AfterAll 里边的语句");
    }
}

1.4 @BeforeEach、@AfterEach

@BeforeEach:当前的方法需要在每个用例执行之前都执行一次

@AfterEach:当前的方法需要在每个用例执行之后都执行一次

import org.junit.jupiter.api.*;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
public class JUnitDemo1 {
    @Test
    void Test01() {
        System.out.println("这是 JunitDemo1 里的 Test01");
    }
    @Test
    void Test02() {
        System.out.println("这是 JunitDemo1 里的 Test02");
    }
    @Disabled
    void Test03() {
        WebDriver webDriver = new ChromeDriver();
        webDriver.get("https://www.baidu.com");
        webDriver.findElement(By.cssSelector("#kw")).sendKeys("521");
        webDriver.findElement(By.cssSelector("#su")).click();
    }
    @BeforeAll
    static void SetUp() {
        System.out.println("这是我们 BeforeAll 里边的语句");
    }
    @AfterAll
    static void TearDown() {
        System.out.println("这是我们 AfterAll 里边的语句");
    }
    @BeforeEach
    void BeforeEachTest() {
        System.out.println("这是 BeforeEach 里边的语句");
    }
    @AfterEach
    void AfterEachTest() {
        System.out.println("这是 AfterEach 里边的语句");
    }
}

2.参数化

参数化就是尽可能的通过一个用例,多组参数来模拟用户的行为;在使用参数化注解之前需要先用 @parameterizedTest 声明该方法为参数化方法,然后再通过注解提供数据来源

使用 @parameterizedTest 需要在 pom.xml 文件中进行配置(记得配置完要进行刷新):

<!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-params -->
<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter-params</artifactId>
    <version>5.9.2</version>
</dependency>

 

2.1 单参数

单参数:@ValueSource(数据类型方法={参数1,参数2…})

import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;

public class JUnitDemo2 {
    //单参数:@ValueSource(数据类型方法={参数1,参数2…})
    @ParameterizedTest
    @ValueSource(ints = {1, 2, 3})
    void Test01(int num) {
        System.out.println(num);
    }
    @ParameterizedTest
    @ValueSource(strings = {"1", "2", "3"})
    void Test02(String number) {
        System.out.println(number);
    }

}

2.2 CSV 获取参数

假设上述参数有很多,在注解处手动编写数据源就有些不方便,我们这时就可以借助第三方csv文件来读取数据源

CSV 获取参数:@CsvFileSource(resources = "____.csv")

这个时候我们需要在 main 文件下 resources 中创建一个 test.csv 文件.csv 和 参数必须相同):

张三1,李四1,王五1
张三2,李四2,王五2

代码编写: 

import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvFileSource;
//参数化

public class JUnitDemo2 {
    @ParameterizedTest
    @CsvFileSource(resources = "test.csv")
    void Test03(String name) {
        System.out.println(name);
    }

}

 此时我们就把所有的内容都打印出来了;

2.3 方法获取参数

@CsvFileSource、@ValueSource 只能传递同种类型的参数,那么我们想要传多种参数,那么可以用方法获取参数

方法获取参数:@MethodSource("Generator")

import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import java.util.stream.Stream;

public class JUnitDemo2 {
    public static Stream<Arguments> Generator() {
        return Stream.of(Arguments.arguments(1, "张三"),
                Arguments.arguments(2, "李四"),
                Arguments.arguments(3, "王五")
        );
    }

    @ParameterizedTest
    @MethodSource("Generator")
    void Test04(int num, String name) {
        System.out.println(num + ":" + name);
    }

}

2.4 多参数

多参数:@CsvSource({“数据组合1”,“数据组合2”…}),每个双引号是一组参数(测试用例)

import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.*;
import java.util.stream.Stream;
public class JUnitDemo2 {
    //多参数:@CsvSource({“数据组合1”,“数据组合2”…})
    @ParameterizedTest
    @CsvSource({"1, 张三", "2, 李四", "3, 王五"})
    void manyTest(int num, String name) {
        System.out.println("num:" + num + ", name:" + name);
    }

}

3.测试用例的执行顺序

我们看以下代码:

此时我们看到打印的依次是 A、B、C 

此时我们看到打印的还是 A、B、C 

所以 测试用例的执行顺序并不会按照我们编写代码的顺序来执行

3.1 顺序执行:@TestMethodOrder(MethodOrderer.OrderAnnotation.class)

如果在实际测试中,我们需要完成连贯的多个步骤的测试,是需要规定测试用例执行的顺序的,可以通过 @order 注解来实现排序

  • 先使用注解说明当前类下所有的用例需要使用 @order 注解来进行排序(注意:该注解必须要用在类上)
  • 然后通过 @order 来指定用例的具体顺序

顺序执行:@TestMethodOrder(MethodOrderer.OrderAnnotation.class),然后再每次执行的时候添加 @order(执行顺序)

import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class JUnitDemo1 {
    @Order(2)
    @Test
    void test03() {
        System.out.println("C");
    }
    @Order(3)
    @Test
    void test01() {
        System.out.println("A");
    }
    @Order(1)
    @Test
    void test02() {
        System.out.println("B");
    }
}

这个时候我们通过 @Order 来设置执行顺序,按照这个思路,我们得到的结果为 B -> C -> A

3.2 随机执行:@TestMethodOrder(MethodOrderer.class)

随机执行@TestMethodOrder(MethodOrderer.class),也就是我们看到的一开始的执行顺序

import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;
@TestMethodOrder(MethodOrderer.class)
public class JUnitDemo2 {
    @Test
    void test03() {
        System.out.println("C");
    }
    @Test
    void test01() {
        System.out.println("A");
    }
    @Test
    void test02() {
        System.out.println("B");
    }
}

 因此,如果不写 @TestMethodOrder(MethodOrderer.OrderAnnotation.class) 则是随即执行

4.断言

检查测试方法的期望结果值真实返回值,通过 Assertions 类实现

  • 断言匹配/不匹配:assertEquals()、assertNotEquals()
  • 断言结果为真/为假:assertTrue()、assertFalse()
  • 断言结果为空/非空:assertNull()、assertNotNull()
public class JUnitDemo3 {
    @Test
    void test01() {
        Assertions.assertTrue(1 == 1);
    }
    @Test
    void test02() {
        Assertions.assertTrue(2 == 1);
    }
}

 在这里我们可以看到 预期和结果 是否相同

5.测试套件

当我们一个类中有多个测试用例时,我们不可能挨个去运行,那样将会很耗费时间,这时我们就需要 测试套件 来指定类或者指定包名来运行类下或者包下的所有测试用例。

如果要使用测试套件,首先我们需要先创建一个类,通过 @Suite 注解标识该类为测试套件类(而不是测试类)

使用测试套件,需要引入依赖

<!-- https://mvnrepository.com/artifact/org.junit.platform/junit-platform-suite -->
<dependency>
    <groupId>org.junit.platform</groupId>
    <artifactId>junit-platform-suite</artifactId>
    <version>1.9.1</version>
</dependency>

还需要引入依赖(使用 suite 需要引入 引擎engine 依赖):

<!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-engine -->
<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter-engine</artifactId>
    <version>5.9.1</version>
</dependency>

5.1 通过 class 运行测试用例

使用 @SelectClasses({指定类, 指定类, 指定类})

JUnitDemo1:

@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class JUnitDemo1 {
    @Order(2)
    @Test
    void test03() {
        System.out.println("C");
    }
    @Order(3)
    @Test
    void test01() {
        System.out.println("A");
    }
    @Order(1)
    @Test
    void test02() {
        System.out.println("B");
    }
}

JUnitDemo4:

public class JUnitDemo4 {
    public static Stream<Arguments> Generator() {
        return Stream.of(Arguments.arguments(1, "张三"),
                Arguments.arguments(2, "李四"),
                Arguments.arguments(3, "王五")
        );
    }

    @ParameterizedTest
    @MethodSource("Generator")
    void Test04(int num, String name) {
        System.out.println(num + ":" + name);
    }
}

RunSuite:

@Suite
@SelectClasses({JUnitDemo4.class, JUnitDemo1.class})
public class RunSuite {

}

此时就是先执行 JUnitDemo4,再执行 JUnitDemo1

5.2 通过包运行测试用例

@SelectPackages(value = {"包1", "包2","..."})

JUnit1 包下 Test1:

public class Test1 {
    @Test
    void test1() {
        System.out.println("JUnit1 package Test1 test1");
    }
}

JUnit2 包下 Test2:

public class Test2 {
    @Test
    void test2() {
        System.out.println("JUnit2 package Test2 test2");
    }
}

RunSuite2:

@Suite
@SelectPackages(value = {"JUnit1", "JUnit2"})
public class RunSuite2 {
}

此时先执行 JUnit1 包下 Test1 ,再执行 JUnit2 包下 Test2

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

应收账款天数和应付账款天数和现金比率和速动比率

应收账款和应付账款天数 应收账款天数计算公式为&#xff1a; 应收账款天数 平均应收账款 * 360 除以 销售额 应收账款天数&#xff08;DOS&#xff09;显示公司需要多少天才能从客户那里收回账款&#xff0c;所以应收账款天数增加的时候&#xff0c;表明应收账款管理出现恶化…

Pyside6-第二篇-QPushButton一个普通按钮

今天是Pyside6的第二篇内容。一起来看一个普通的按钮。 QPushButton。 from PySide6.QtWidgets import QWidget, QApplication, QPushButtonapp QApplication([])win QWidget() win.setWindowTitle("QPushButton按钮")btn QPushButton(win) btn.setText("触发…

浅析多模态机器学习

GPT-4的发布给ChatGPT带来了又一次飞跃&#xff0c;ChatGPT不仅支持文字输入&#xff0c;还能看得懂图片、甚至是漫画、梗图&#xff0c;以GPT-4为代表的多模态大模型非常强大。多模态大模型就是指模型可以处理多种结构/类型的数据&#xff0c;例如GPT-4&#xff0c;它既可以处…

Hugging Face 介绍

Hugging Face 是一家在自然语言处理和人工智能领域著名的公司&#xff0c;以开发开源的软件库和工具为主要贡献&#xff0c;其中最受欢迎的是 Transformers 库&#xff0c;广泛应用于诸如语言翻译、情感分析和问答等多种自然语言处理任务。此外&#xff0c;Hugging Face 还开发…

c++ 11标准模板(STL) std::map(七)

定义于头文件<map> template< class Key, class T, class Compare std::less<Key>, class Allocator std::allocator<std::pair<const Key, T> > > class map;(1)namespace pmr { template <class Key, class T, clas…

100种思维模型之顺势而为思维模型-68

“我领悟到&#xff0c;人是不能推着石头往上走的&#xff0c;这样会很累&#xff0c;而且会被山上随时滚落的石头给打下去。要做的是&#xff0c;先爬到山顶&#xff0c;随便踢块石头下去。”——雷军说。 “只要站在风口上&#xff0c;猪也能飞起来“。——雷军。 顺势而为是…

JetBrains的多数据库管理和SQL工具DataGrip 2023版本在Linux系统的下载与安装配置教程

目录 前言一、DataGrip安装二、使用配置总结 前言 DataGrip是一款多数据库管理和SQL工具&#xff0c;适用于不同类型的数据库。它提供了丰富的功能和工具&#xff0c;可以帮助开发人员更高效地管理数据库、编写SQL查询和执行数据操作。注&#xff1a;已在CentOS7.9和Ubuntu20.…

海思sdk快速上手

mpp&#xff1a;视频H.264的编码压缩 1.看linux、uboot的文档 2.移植SDK到ubuntu 2.1、三个脚本 source sdk.unpack解压 2.2、osdrv/Makefile和readme make OSDRV_CROSSarm-hisiv300-linux CHIPhi3518ev200 all报错 参考&#xff1a;ubuntu16.04 编译错误: /bin/sh: 1: pushd…

《写作脑科学:如何用脑科学改善写作能力》

《写作脑科学&#xff1a;如何用脑科学改善写作能力》 前言引言概述评价结论 &#x1f3d8;️&#x1f3d8;️个人简介&#xff1a;以山河作礼。 &#x1f396;️&#x1f396;️:Python领域新星创作者&#xff0c;CSDN实力新星认证&#xff0c;阿里云社区专家博主 前言 &…

【C++】23.C++的IO流(补)

1.C标准IO流 C标准库提供了4个全局流对象cin、cout、cerr、clog&#xff0c;使用cout进行标准输出&#xff0c;即数据 从内存流向控制台(显示器)。使用cin进行标准输入即数据通过键盘输入到程序中&#xff0c;同时C 标准库还提供了cerr用来进行标准错误的输出&#xff0c;以…

chatgpt赋能python:Python中OP怎么用

Python中OP怎么用 Python是一种高级编程语言&#xff0c;可用于快速开发网站、桌面应用程序、网络爬虫和数据科学等各种领域。Python作为一种功能强大的编程语言&#xff0c;其操作符&#xff08;OP&#xff09;是一个必须学习的基本知识点。本文将介绍Python中OP的使用方法。…

DataTables表格库(一)

目录 1、零配置使用 1.2、代码 1.3、步骤 1.4、效果 2、禁用分页&#xff0c;排序等功能的配置 2.1、说明 2.2、代码 2.3、效果 3、默认排序配置 3.1、说明 3.2、代码 3.3、效果 4、多列排序 4.1、说明 4.2、代码示例 4.3、效果 5、多个表格 5.1、说明 5.2、…

【源码解析】SpringBoot使用DeferredResult实现长轮询的原理分析

使用背景 在Nacos配置更新和Apollo的配置更新&#xff0c;我们可以看到长轮询&#xff08;长连接&#xff09;的身影。长连接的实现可以节约系统资源&#xff0c;长连接可以在连接建立后持续通信&#xff0c;避免频繁地建立和断开连接&#xff0c;减少系统开销。使用长连接可以…

LAMP的运用

LAMP的运用 一、LAMP二、编译安装apache http服务三、编译安装mysqld服务四、编译安装PHP解析环境五、安装论坛 一、LAMP LAMP架构是目前成熟的企业网站应用模式之一&#xff0c;指的是协同工作的一整套系统和相关软件&#xff0c;能够提供动态Web站点服务及其应用开发环境。L…

《痞子衡嵌入式半月刊》 第 77 期

痞子衡嵌入式半月刊&#xff1a; 第 77 期 这里分享嵌入式领域有用有趣的项目/工具以及一些热点新闻&#xff0c;农历年分二十四节气&#xff0c;希望在每个交节之日准时发布一期。 本期刊是开源项目(GitHub: JayHeng/pzh-mcu-bi-weekly)&#xff0c;欢迎提交 issue&#xff0c…

【JavaSE】Java基础语法(二十八):HashSet集合

文章目录 1. HashSet集合概述和特点2. HashSet集合的基本应用3. 哈希值4. HashSet集合存储学生对象并遍历【应用】 1. HashSet集合概述和特点 底层数据结构是哈希表存取无序不可以存储重复元素没有索引,不能使用普通for循环遍历 2. HashSet集合的基本应用 存储字符串并遍历 …

Pytorch深度学习之神经网络入门详解

目录 Pytorch 入门 1.将每个图片的label作为txt文件写入另外一个文件夹&#xff08;txt文件名与图片文件名相同&#xff09; 2.tensorboard的summary writer 3.torchvision中的transforms 4.DataLoader 5.神经网络-卷积层Conv2d 6.最大池化层 7.非线性激活函数Relu 9.…

微信的大动作,很多人要颤抖了

4月25日&#xff0c;微信团队发布关于微信公众号营销内容合规规范通知&#xff0c;要求公众号在投放商业广告时需要标注广告字样。 刚开始觉得也没啥&#xff0c;无非就是加个广告的字样&#xff0c;让消费者可以及时识别出来&#xff0c; 但从效果来看&#xff0c;似乎效果并不…

华为OD机试真题B卷 Java 实现【猜密码】

一、题目描述 小杨申请了一个保密柜,但是他忘记了密码。只记得密码都是数字,而且所有数字都是不重复的。 请你根据他记住的数字范围和密码的最小数字数量,帮他算下有哪些可能的组合,规则如下: 输出的组合都是从可选的数字范围中选取的,且不能重复;输出的密码数字要按照…

意外的坚持,意外的收获!

前言&#xff1a; 转眼间&#xff0c;2023就快过了一半&#xff0c;回忆间感觉跟过完年没多久一样&#xff1b;时间是真的过的快...... 简单总结一下最近&#xff1a; 一、锻炼身体&#xff1a; 最近这段时间开始恢复锻炼身体&#xff0c;现在感觉一天下班回来&#xff0c;身体…