【测试开发篇9】Junit框架
目录
一、认识Junit框架
Junit和Selenium的关系是什么
导入Junit框架+common-io包
二、Junit框架的使用
2.1Junit有哪些常用注解
2.1.1@Test注解
2.1.2BeforeEach
2.1.3@BeforeAll
2.1.4@AfterAll
2.1.5@AfterEach
2.2Junit的断言
Assertions.assertEquals(期待值,真实值);
2.2.1Assertions.assertNotEquals("百度一下",text)
2.2.2Assertions.assertTrue(text.equals("百度一下"))
2.2.3Assertions.assertNull(a);
三、用例的执行顺序
①针对方法的排序
为什么需要用到juit的排序功能
四、测试套件(Suit)
@Suite
@SelectClasses({待测试的类.class})
@SelectPackages("包名")
五、参数化
5.1@ParameterizedTest、@ValueSource(strings = {})
5.2@CsvSource(value={"第一组数据","第二组数据"})
如果参数当中包含逗号:",",就需要使用单引号转义字符串
5.3读取文件参数:@CsvFileSource(resources="/文件名称")
5.3.1读取其他磁盘文件的操作:指定文件为files=...
5.4动态参数(单参数版本)
5.5动态参数(多参数版本)
六、对于重要测试场景的截图
第一步:定位到需要的页面
第二步:调用getSrceenshotAs方法,传入的擦参数是OutputTpye.FILE;
第三步:新建一个File类,指定路径;
第四步:调用copyFile方法,把生成的文件放到指定的目录当中
一、认识Junit框架
Junit是一个开源的Java语言的单元测试框架。
回顾一下,单元测试就是在编码阶段,一般情况下,由开发进行的测试。
Junit和Selenium的关系是什么
Junit是单元测试框架,而selenium是web自动化测试框架。如果把selenium比作灯泡,那么junit就是电灯。因此:一般情况下,junit负责运行selenium脚本编写的代码。
导入Junit框架+common-io包
<dependency><groupId>commons-io</groupId><artifactId>commons-io</artifactId><version>2.6</version></dependency><dependency><groupId>org.seleniumhq.selenium</groupId><artifactId>selenium-java</artifactId><version>4.8.1</version></dependency><dependency><groupId>org.junit.jupiter</groupId><artifactId>junit-jupiter-api</artifactId><version>${junit.version}</version><scope>test</scope></dependency><dependency><groupId>org.junit.platform</groupId><artifactId>junit-platform-suite</artifactId><version>1.8.2</version><scope>test</scope></dependency><dependency><groupId>org.junit.jupiter</groupId><artifactId>junit-jupiter-params</artifactId><version>5.8.2</version><scope>test</scope></dependency><dependency><groupId>org.junit.jupiter</groupId><artifactId>junit-jupiter-engine</artifactId><version>${junit.version}</version><scope>test</scope></dependency> 
二、Junit框架的使用
2.1Junit有哪些常用注解
2.1.1@Test注解
这一个注解作用于方法上面,表示这个方法是一个测试用例。当@Test注解作用在一个方法上面的时候,表示这一个方法是可以直接运行的,无需通过main方法来调用。

2.1.2BeforeEach
在执行每一个被@Test修饰的方法之前,都会执行一次@BeforeEach注释的方法。
@BeforeEachvoid aaa(){System.out.println("pre");}@Testvoid bbb(){System.out.println("bbb");}@Testvoid ccc(){System.out.println("ccc");} 
每执行一个@Test之前,就需要执行一次@BeforeEach注释的方法
运行类上面的运行按钮:

2.1.3@BeforeAll
首先,被@BeforeAll注释的方法一定是静态的。
其次,不同于@BeforeEach的是,@BeforeAll注释的方法一定是静态的,并且只会在加载外部类的时候执行一次,并不会在每一个方法执行之前再次执行了。
public class Test1 {@BeforeAllstatic void aaa(){System.out.println("pre");}@Testvoid bbb(){System.out.println("bbb");}@Testvoid ccc(){System.out.println("ccc");}
} 

2.1.4@AfterAll
被这个注解修饰的方法也必须是静态的,在每一个@Test之后进行修饰。
public class Test1 {@BeforeAllstatic void aaa(){System.out.println("pre");}@Testvoid bbb(){System.out.println("bbb");}@Testvoid ccc(){System.out.println("ccc");}@AfterAllstatic void afterAll(){System.out.println("end...");}
} 
运行结果:

2.1.5@AfterEach
同理,在每一个@Test注释的方法执行结束的末尾,都会执行一次@AfterEach注释的方法。
public class Test1 {@BeforeEachvoid aaa(){System.out.println("pre");}@Testvoid bbb(){System.out.println("bbb");}@Testvoid ccc(){System.out.println("ccc");}@AfterEachvoid afterAll(){System.out.println("end...");}
} 
运行结果:

2.2Junit的断言
写自动化测试,结果要么是成功的,要么是失败的,不存在成功一半的情况。
那么就需要使用到断言:assert,断言预期结果和真实结果是否一致。
Assertions.assertEquals(期待值,真实值);
当期待值和真实值一致的时候,这个断言才不会抛出异常;
当期待值和真实值不一致的时候,就会抛出异常;
代码实现:
public class Test2 {FirefoxDriver driver;@BeforeEachpublic void get(){driver=new FirefoxDriver();//捕捉到这一个页面driver.get("https://www.baidu.com");}@Testpublic void testOne(){//尝试获取"百度一下"的文本框String text=driver.findElement(By.cssSelector("#su")).getAttribute("value");//使用AssertEquals来进行断言Assertions.assertEquals("百度一下",text);}@AfterEachpublic void after(){driver.quit();}
} 
如果运行的结果一致,那么就提示测试用例通过:

2.2.1Assertions.assertNotEquals("百度一下",text)
与Assertions.assertEquals(期待值,真实值)相反。
只有不一致的时候,测试用例才会通过。

2.2.2Assertions.assertTrue(text.equals("百度一下"))
传入的参数应该是一个返回值为boolean类型的表达式;
@Test
public void assertTrueTest(){String text=driver.findElement(By.cssSelector("#su")).getAttribute("value");//如果返回true,那么测试用例通过,否则测试用例不通过Assertions.assertTrue(text.equals("百度一下"));} 
同理,还有AssertFalse
2.2.3Assertions.assertNull(a);
 @Testpublic void assertNull(){String a=null;Assertions.assertNull(a);} 
如果一个引用为null,那么默认测试用例通过。
同理,还有Assertions.assertNotNull(),那么一个引用不为null的时候,测试用例才通过。
三、用例的执行顺序
①针对方法的排序
第一步:在这个类上面添加注解:@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
第二步:
使用@Order(执行顺序)作用在方法上面,表示是第几个执行;
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class Test2 {FirefoxDriver driver;@BeforeEach@Order(1)public void get(){driver=new FirefoxDriver();//捕捉到这一个页面driver.get("https://www.baidu.com");}@Test@Order(2)public void testOne(){//尝试获取"百度一下"的文本框String text=driver.findElement(By.cssSelector("#su")).getAttribute("value");Assertions.assertNotEquals("百度一下",text);}@Test@Order(3)public void assertTrueTest(){String text=driver.findElement(By.cssSelector("#su")).getAttribute("value");//如果返回true,那么测试用例通过,否则测试用例不通过Assertions.assertTrue(text.equals("百度一下"));}@AfterEachpublic void after(){driver.quit();}
} 
为什么需要用到juit的排序功能
如果用例之间存在关联关系(存在耦合)(但是不是绝对有关联关系),那么就需要手动指定用例的执行顺序。因为各个测试用例的执行顺序是无序的。
这样就可以避免出现各个测试用例之间执行顺序不正确的情况。
四、测试套件(Suit)
测试套件,用于把所有的测试用例都执行起来。
@Suite
这一个注解作用于类上面,用于执行所有的测试用例。
@SelectClasses({待测试的类.class})
这个注解和上面的注解需要配合使用,这样才可以一起执行待测试类的测试用例。
当然也可以传递多个.class对象。
@Suite
@SelectClasses({Test1.class,Test2.class})
public class SuitTest {}
 
运行结果:

@SelectPackages("包名")
扫描这一个包下面包含了@Test注解的方法的类。
@Suite
@SelectPackages("TestFile")
public class SuitTest {} 
但是扫描的包不可以和当前的类在同一个包下面;
需要注意的是,这种情况下面,被扫描的类一定是xxxTest这样命名的,否则是扫描不到的。

五、参数化
对于一个测试用例,可能会测试传入的参数是多种的情况;
例如对于一个文本框进行测试,可以测试多种输入的情况:
如下图:如果为每一个输入的name都定义一个方法,那么就显得非常冗余,于是就引入了参数化。

5.1@ParameterizedTest、@ValueSource(strings = {})
第一个注解@Parameterized作用在方法上面,用来表示这个方法支持传入多个参数;
第二个注解@ValueSource用于指定传入参数的类型;例如:strings={}就表示传入的是一个string类型的数组;
ints={2,3,4,5}表示传入的参数是一个int类型的数组;
但是,同一个@ValueSource注解当中只支持一种数据类型。


运行结果:
5.2@CsvSource(value={"第一组数据","第二组数据"})
其中,每一组数据当中对应方法传入的参数的值。采用","来分割。
@ParameterizedTest@CsvSource(value = {"小明,20","小红,30","小李,40"})public void printStringAndInteger(String name,int age){System.out.println("name:"+name+";age="+age);} 

当然,一组数据当中的分隔符也不一定采用系统默认的","分割,也可以采用自定义的分隔符。
@ParameterizedTest@CsvSource(value = {"小明-20","小红-20","小李-40"},delimiter = '-')public void printStringAndAge(String name,int age){System.out.println("name:"+name+";age="+age);} 
用户自定义的分隔符:

如果参数当中包含逗号:",",就需要使用单引号转义字符串

5.3读取文件参数:@CsvFileSource(resources="/文件名称")
第一步:在resources目录下面新建一个文件,并且指定名称;
第二步:在文件当中以逗号的方式分割每一组参数;


然后运行程序:

5.3.1读取其他磁盘文件的操作:指定文件为files=...
    @ParameterizedTest@CsvFileSource(files = "E:\\OJSystem\\src\\main\\resources\\my.csv")public void printStringAndAge3(String name,int age){System.out.println("name:"+name+";age="+age);} 
5.4动态参数(单参数版本)
第一步:定义提供数据的方法,必须声明为静态;返回值为一个Stream对象;方法内部调用Stream.of(参数列表);
第二步:定义dyNatickTest(String x)方法获取参数;并用@MethodSource()指定
第三步:输出参数。

@ParameterizedTest@MethodSource("methodDemo")void dyNatickTest(String x){System.out.println(x);}static Stream<String> methodDemo(){return Stream.of("张三","李四","王五");} 
如果@MethodSource当中不指定参数的名称,那么就会调用跟测试用例同名的静态方法

5.5动态参数(多参数版本)
第一步:新建一个测试方法,并且指定多个参数。使用@ParameterizedTest和@MethodSource注解同时作用
第二步:新建一个和测试用例同名的静态方法;
第三步:在静态方法当中调用Stream.of()方法,并且传入的参数为多个Arguments.arguments(第一步创建方法的参数列表)

代码实现:
@ParameterizedTest@MethodSourcevoid paramsTest(String name,int age){System.out.println("name:"+name+";age :"+age);}/*** 多参数的版本* Stream对象@return*/static Stream<Arguments> paramsTest(){return Stream.of(Arguments.arguments("lucy",29),Arguments.arguments("lili",30),Arguments.arguments("lisi",40));} 
六、对于重要测试场景的截图
第一步:定位到需要的页面
第二步:调用getSrceenshotAs方法,传入的擦参数是OutputTpye.FILE;
第三步:新建一个File类,指定路径;
第四步:调用copyFile方法,把生成的文件放到指定的目录当中
@Testpublic void screenShortTest() throws IOException, InterruptedException {//百度搜索关键字driver.findElement(By.cssSelector("#kw")).sendKeys("selenium");driver.findElement(By.cssSelector("#su")).click();//屏幕截图,把截图的文件存放到指定的位置//以文件的形式存储File srcFile=driver.getScreenshotAs(OutputType.FILE);//把截图的文件存放到指定的目录下面File destFile=new File("E:/OJSystem/src/test/Files/img.png");Thread.sleep(1000);FileUtils.copyFile(srcFile,destFile);} 
相关文章:
【测试开发篇9】Junit框架
目录 一、认识Junit框架 Junit和Selenium的关系是什么 导入Junit框架common-io包 二、Junit框架的使用 2.1Junit有哪些常用注解 2.1.1Test注解 2.1.2BeforeEach 2.1.3BeforeAll 2.1.4AfterAll 2.1.5AfterEach 2.2Junit的断言 Assertions.assertEquals(期待值&#…...
《Spring MVC》 第五章 实现RESTful
前言 教授大家如何实现RESTful 1、什么是RESTful resource Representational State Transfer 的缩写,就是“表现层资源表述状态转移” 1.1、Resource(资源) web应用的文件,uri定位 1.2、Representation(资源的描…...
Last Week in Milvus
What’s New Core Updates #23353 在 2.3 版本中, milvus 和 knowhere 引擎会移除了 Annoy 索引。Annoy 索引在性能和召回率方面均不如 IVF、HNSW 等索引,维护成本比较高所以经过讨论决定在 2.3 中移出 Annoy 索引的支持,有使用的用户要注意…...
Cursor IDE一个GPT4人工智能自动程序编辑器
让我们来了解一下Cursor IDE是什么。Cursor IDE是一个新型的编程工具,可以通过它生成、编辑以及与人工智能进行交互分析代码。官方网站上的三个单词“Build Software. Fast.”(快速构建软件)以及“Write, edit, and chat about your code wit…...
PPO算法-理论篇
1. Policy Gradient 【李宏毅深度强化学习笔记】1、策略梯度方法(Policy Gradient) 李宏毅深度强化学习-B站 2. PPO PPO 算法 PPO算法更新过程如下: 初始化policy参数 θ 0 \theta^0 θ0在每一步迭代中: 使用 θ k \theta^k …...
【现货】AP6317 同步3A锂电充电芯片 带短温度保护
AP6317是一款面向5V交流适配器的3A锂 离子电池充电器。它是采用800KHz固定频率的同 步降压型转换器,因此具有高达92%以上的充电效 率,自身发热量极小。 包括完整的充电终止电路、自动再充 电和一个精确度达1%的4.2V预设充电电压,内 部集成了防…...
MyBatis详解(2)
8、自定义映射resultMap 8.1、resultMap处理字段和属性的映射关系 若字段名和实体类中的属性名不一致,则可以通过resultMap设置自定义映射 <!--resultMap:设置自定义映射属性:id:表示自定义映射的唯一标识type:查询…...
2023-04-14 使用纯JS实现一个2048小游戏
文章目录 一.实现思路1.2048的逻辑2.移动操作的过程中会有三种情况 二.代码部分:分为初始化部分和移动部分1.初始化部分1.1.生成第一个方块:1.2.生成第二个方块: 2.移动过程部分: 三.实现代码1.HTML部分2.CSS部分3.JS部分3.1.game对象的属性3.2.game对象的start方法3.3.game对象…...
C++入门(3)
C入门 1.auto关键字(C11)1.1. 类型别名的思考1.2. auto简介1.3. auto使用情景1.4. auto的使用细则1.5. auto不能推导的场景 1.auto关键字(C11) 1.1. 类型别名的思考 随着程序越来越复杂,程序中用到的类型也越来越复杂…...
【亲测有效】更新了WIN11之后 右键无 新建WORD,PPT,EXCEL 选项 问题 解决方案
原本正常的正版系统,在昨天4月自动更新安装之后,发现右键找 不到新建文档了,word,ppt,excel都不见了。 看了网上大神的方法 Win11安装了Office右键没有新建Excel选项怎么办? - 知乎 可以解决一部分 官方解决方案,亲…...
2023年4月北京/西安/郑州/深圳CDGA/CDGP数据治理认证考试报名
DAMA认证为数据管理专业人士提供职业目标晋升规划,彰显了职业发展里程碑及发展阶梯定义,帮助数据管理从业人士获得企业数字化转型战略下的必备职业能力,促进开展工作实践应用及实际问题解决,形成企业所需的新数字经济下的核心职业…...
Win10桌面我的电脑怎么调出来?最简单方法教学
Win10桌面我的电脑怎么调出来?有用户发现自己的电脑桌面没有我的电脑这个程序图标,每次要访问磁盘的时候,开启都非常的麻烦。那么怎么将这个图标设置到桌面显示呢?接下来我们一起来看看以下的解决方法吧。 方法一: 在开…...
开启单细胞及空间组学行业发展黄金时代!首届国际单细胞及空间组学大会在穗闭幕
2023年4月16日,首届TICSSO国际单细胞及空间组学大会圆满闭幕,本次大会吸引了2000余位来自产、学、研、资、医、政、媒等业界人士齐聚羊城,注册总人数5398人,网络播放总量达548245人次,网络观看覆盖美国、德国、日本、澳…...
YOLOv8 更换主干网络之 GhostNetV2
《GhostNetV2:Enhance Cheap Operation with Long-Range Attention》 轻量级卷积神经网络(CNN)是专门为在移动设备上具有更快推理速度的应用而设计的。卷积操作只能捕捉窗口区域内的局部信息,这防止了性能的进一步提高。将自注意力引入卷积可以很好地捕捉全局信息,但这将大…...
高级服务框架(黑马)
一、修改order-service服务 修改OrderService,让其监听Nacos中的sentinel规则配置。 具体步骤如下: 1.引入依赖 在order-service中引入sentinel监听nacos的依赖: <dependency><groupId>com.alibaba.csp</groupId><…...
Go语言面试题--基础语法(29)
文章目录 1.下面的代码有什么问题?2.下面代码最后一行输出什么?请说明原因3.下面代码有什么问题?4.下面的代码输出什么? 1.下面的代码有什么问题? func main() {data : []int{1,2,3}i : 0ifmt.Println(data[i]) }参考…...
毕业生招聘信息的发布与管理系统(论文+设计)
前 言 当今,人类社会已经进入信息全球化和全球信息化、网络化的高速发展阶段。丰富的网络信息已经成为人们工作、生活、学习中不可缺少的一部分。人们正在逐步适应和习惯于网上贸易、网上购物、网上支付、网上服务和网上娱乐等活动,人类的许多社会活动…...
mysql安全加固配置文档(完结)
4. MySQL 权限安全配置 4.1. 确保只有管理员账号有所有数据库的访问权限 建议理由 除了管理员账号,其他用户没必要有所有数据库的访问权限。过高的权限会导致安全问题。检查方法 SELECT user, host FROM MySQL.user WHERE (Select_priv Y) OR (Insert_priv Y) …...
CAPL函数在实现AES加密算法时遇到的各种问题(c++中符号的含义,AES算法中padding的问题等)
本来打算把AES算法的代码移植到CAPL中的,文章:https://blog.csdn.net/qq_28205153/article/details/55798628?spm=1001.2014.3001.5506里有非常详细的代码。但是一来太麻烦,二来没必要,因为CAPL提供了Security安全相关的函数: 这里面就提供了AES加密算法的接口函数,使用…...
二叉排序树(二叉查找树)基本操作_20230417
二叉排序树(二叉查找树)基本操作_20230417 前言 二叉排序树首先是一颗二叉树,它不同于常规二叉树的地方在于,如果左子树不为空,那么左子树上所有结点的值都不大于根节点的值,如果右子树不为空,…...
day52 ResNet18 CBAM
在深度学习的旅程中,我们不断探索如何提升模型的性能。今天,我将分享我在 ResNet18 模型中插入 CBAM(Convolutional Block Attention Module)模块,并采用分阶段微调策略的实践过程。通过这个过程,我不仅提升…...
【7色560页】职场可视化逻辑图高级数据分析PPT模版
7种色调职场工作汇报PPT,橙蓝、黑红、红蓝、蓝橙灰、浅蓝、浅绿、深蓝七种色调模版 【7色560页】职场可视化逻辑图高级数据分析PPT模版:职场可视化逻辑图分析PPT模版https://pan.quark.cn/s/78aeabbd92d1...
Python基于历史模拟方法实现投资组合风险管理的VaR与ES模型项目实战
说明:这是一个机器学习实战项目(附带数据代码文档),如需数据代码文档可以直接到文章最后关注获取。 1.项目背景 在金融市场日益复杂和波动加剧的背景下,风险管理成为金融机构和个人投资者关注的核心议题之一。VaR&…...
【Redis】笔记|第8节|大厂高并发缓存架构实战与优化
缓存架构 代码结构 代码详情 功能点: 多级缓存,先查本地缓存,再查Redis,最后才查数据库热点数据重建逻辑使用分布式锁,二次查询更新缓存采用读写锁提升性能采用Redis的发布订阅机制通知所有实例更新本地缓存适用读多…...
基于IDIG-GAN的小样本电机轴承故障诊断
目录 🔍 核心问题 一、IDIG-GAN模型原理 1. 整体架构 2. 核心创新点 (1) 梯度归一化(Gradient Normalization) (2) 判别器梯度间隙正则化(Discriminator Gradient Gap Regularization) (3) 自注意力机制(Self-Attention) 3. 完整损失函数 二…...
python爬虫——气象数据爬取
一、导入库与全局配置 python 运行 import json import datetime import time import requests from sqlalchemy import create_engine import csv import pandas as pd作用: 引入数据解析、网络请求、时间处理、数据库操作等所需库。requests:发送 …...
实战三:开发网页端界面完成黑白视频转为彩色视频
一、需求描述 设计一个简单的视频上色应用,用户可以通过网页界面上传黑白视频,系统会自动将其转换为彩色视频。整个过程对用户来说非常简单直观,不需要了解技术细节。 效果图 二、实现思路 总体思路: 用户通过Gradio界面上…...
redis和redission的区别
Redis 和 Redisson 是两个密切相关但又本质不同的技术,它们扮演着完全不同的角色: Redis: 内存数据库/数据结构存储 本质: 它是一个开源的、高性能的、基于内存的 键值存储数据库。它也可以将数据持久化到磁盘。 核心功能: 提供丰…...
MySQL的pymysql操作
本章是MySQL的最后一章,MySQL到此完结,下一站Hadoop!!! 这章很简单,完整代码在最后,详细讲解之前python课程里面也有,感兴趣的可以往前找一下 一、查询操作 我们需要打开pycharm …...
Python训练营-Day26-函数专题1:函数定义与参数
题目1:计算圆的面积 任务: 编写一个名为 calculate_circle_area 的函数,该函数接收圆的半径 radius 作为参数,并返回圆的面积。圆的面积 π * radius (可以使用 math.pi 作为 π 的值)要求:函数接收一个位置参数 radi…...
