文章目录
- 一.前言
- 二.selenium介绍
- 三.selenium的组成部分
- 四.Selenium的环境搭建
- 下载浏览器
- 配置环境变量
- 验证环境是否搭建成功
- 五.Selenium的API
- 打开浏览器
- 元素的定位
- 操作测试对象
- 等待操作
- 信息获取
- 鼠标操作
- 键盘操作
- 选项操作
- 浏览器操作
- 六.需要用到的包
一.前言
自动化测试指软件测试的自动化,在预设状态下运行应用程序或者系统,预设条件包括正常和异常,最后评估运行结果。将人为驱动的测试行为转化为机器执行的过程.
自动化测试包括UI自动化,接口自动化,单元测试自动化。按照这个金字塔模型来进行自动化测试规划,可以产生最佳的自贡话测试产出投入比(ROI),可以用较少的投入获得很好的收益。
当然这篇文章主要会介绍基于UI的自动化测试框架的使用,大家敬请期待.
二.selenium介绍
以下是Selenium的简单介绍
Selenium 通过使用 WebDriver 支持市场上所有主流浏览器的自动化。 Webdriver 是一个 API 和协议,它定义了一个语言中立的接口,用于控制 web 浏览器的行为。 每个浏览器都有一个特定的 WebDriver 实现,称为驱动程序。 驱动程序是负责委派给浏览器的组件,并处理与 Selenium 和浏览器之间的通信。
这种分离是有意识地努力让浏览器供应商为其浏览器的实现负责的一部分。 Selenium 在可能的情况下使用这些第三方驱动程序, 但是在这些驱动程序不存在的情况下,它也提供了由项目自己维护的驱动程序。
Selenium 框架通过一个面向用户的界面将所有这些部分连接在一起, 该界面允许透明地使用不同的浏览器后端, 从而实现跨浏览器和跨平台自动化。
具体关于selenium的详细介绍大家可以参考这个网站
相关介绍和教程
三.selenium的组成部分
我这里讲的组成部分大致参考selenium的官网进行介绍的.
WebDriver
如果您开始使用桌面网站测试自动化, 那么您将使用 WebDriver APIs. WebDriver 使用浏览器供应商提供的浏览器自动化 API 来控制浏览器和运行测试. 这就像真正的用户正在操作浏览器一样. 由于 WebDriver 不要求使用应用程序代码编译其 API, 因此它本质上不具有侵入性. 因此, 您测试的应用程序与实时推送的应用程序相同.
这里的WebDriver有点说法,因为我们还是得去了解,WebDriver的原理.
我们可以把WebDriver驱动浏览器类比成出租车司机开出租车。
这里有三个角色.
乘客:他/她告诉出租车司机去哪里,大概怎么走
出租车司机:他按照乘客的要求来操控出租车
出租车:出租车按照司机的操控完成真正的行驶,把乘客送到目的地
总的来说,WebDriver里面也有三个角色.
工程师写的自动化测试代码:自动化测试代码发送请求给浏览器的驱动(比如火狐驱动、谷歌驱动)
浏览器的驱动:它来解析这些自动化测试的代码,解析后把它们发送给浏览器
浏览器:执行浏览器驱动发来的指令,并最终完成工程师想要的操作。
具体还是要用图来说明
1.对于每一条Selenium脚本,一个http请求会被创建并且发送给浏览器的驱动
⒉.浏览器驱动中包含了一个HTTP Server,用来接收这些http请求
3.HTTP Server接收到请求后根据请求来具体操控对应的浏览器
4.浏览器执行具体的测试步骤
5.浏览器将步骤执行结果返回给HTTP Server
6.HTTP Server又将结果返回给Selenium的脚本,如果是错误的http代码我们就会在控制台看到对应的报错信息。
Selenium IDE
Selenium IDE (Integrated Development Environment 集成开发环境) 是用来开发 Selenium 测试用例的工具. 这是一个易于使用的 Chrome 和 Firefox 浏览器扩展, 通常是开发测试用例最有效率的方式. 它使用现有的 Selenium 命令记录用户在浏览器中的操作, 参数由元素的上下文确定. 这不仅节省了开发时间, 而且是学习 Selenium 脚本语法的一种很好的方法.
具体的细节,大家可以参考这个链接
介绍
IDE Grid
Selenium Grid允许您在不同平台的不同机器上运行测试用例. 可以本地控制测试用例的操作, 当测试用例被触发时, 它们由远端自动执行.
当开发完WebDriver测试之后, 您可能需要在多个浏览器和操作系统的组合上运行测试. 这就是 Grid 的用途所在.
具体的详细介绍,大家可以点击这个链接进去学习,我们这里就不做过多赘述了
IDE Grid
四.Selenium的环境搭建
下载浏览器
1.我这里直接丢几个常用的浏览器下载软件
Firefox
google
Bing
在下载完浏览器之后,我们需要根据相应的浏览器版本,去下载驱动
2.下载驱动
我这里的浏览器版本如下:
这里直接给出下载驱动的地址,记住一定要和浏览器版本一致
驱动下载链接
配置环境变量
解压下载好的驱动压缩包,将下载好的chromedriver.exe放到java系统环境变量下
举例:我的java路径是C:\Program Files\Java\jdk1.8.0_131\bin
验证环境是否搭建成功
- 创建java项目,添加pom文件中添加依赖
<dependencies>
<!-- https://mvnrepository.com/artifact/org.seleniumhq.selenium/selenium-java -->
<!-- https://mvnrepository.com/artifact/org.seleniumhq.selenium/selenium-java -->
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>3.4.0</version>
</dependency>
</dependencies>
- 编写代码运行
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
public class Main {
public static void main(String[] args) {
ChromeOptions options = new ChromeOptions();
options.addArguments("--remote-allow-origins=*");
WebDriver webDriver = new ChromeDriver(options);
webDriver.get("https://www.baidu.com");
}
}
如果打开了浏览器,此时说明安装成功
五.Selenium的API
怎么说呢?我们现在就要应用这个selenium的api了.我们所有的操作都可以认为是在模拟用户去操作浏览器的行为.
打开浏览器
public class Main {
public static void main(String[] args) {
//获取所有请求
ChromeOptions options = new ChromeOptions();
options.addArguments("--remote-allow-origins=*");
WebDriver webDriver = new ChromeDriver(options);
//打开百度首页
webDriver.get("https://www.baidu.com");
}
}
我们首先最重要的就是打开浏览器这个操作,如果打开浏览器的操作都没有成功,那接下来的操作,估计也不太顺利.
元素的定位
当然我们在进行打开浏览器页面之后,我们要针对浏览器的一些页面,进行一些定位.
我们首先来最简单的,试想一下,你打开百度首页,首先要做的事情如下:
1.找到输入框
2.输入搜索内容
3.点击搜索
我们接下来来模拟这几步操作.
private static void test01() {
//获取所有请求
ChromeOptions options = new ChromeOptions();
options.addArguments("--remote-allow-origins=*");
WebDriver webDriver = new ChromeDriver(options);
//1.打开百度首页
webDriver.get("https://www.baidu.com");
//2.找到文本输入框
WebElement element=webDriver.findElement(By.xpath("//*[@id=\"kw\"]"));
// WebElement element=webDriver.findElement(By.cssSelector("#kw"));
element.sendKeys("七龙珠");
//3.找到点击按钮,进行点击
// webDriver.findElement(By.cssSelector("#su"));
webDriver.findElement(By.xpath("//*[@id=\"su\"]")).click();
}
最终上述代码就会跟你去点击百度首页搜索的效果一样.
但这里我想说的其实最重要的元素定位操作,我这段代码中用到了css和xpath的定位方式.我这里就跟大家简单的解释一下,这俩中定位方式的语法.
xpath定位
XPath 使用路径表达式来选取 XML 文档中的节点或节点集。节点是通过沿着路径 (path) 或者步 (steps) 来选取的。
怎么说呢,来一个简单的例子,大家来感受一下xpath的定位.
看一个页面
<?xml version="1.0" encoding="ISO-8859-1"?>
<bookstore>
<book>
<title lang="eng">Harry Potter</title>
<price>29.99</price>
</book>
<book>
<title lang="eng">Learning XML</title>
<price>39.95</price>
</book>
</bookstore>
看具体的我获取这些标签的方法.
具体使用谓语表达式来获取元素
也可以使用 通配符可用来选取未知的 XML 元素。
具体的介绍,可以参考W3C的网站,去具体学习一下XPath的语法.
XPath
CSS定位
CSS定位是一种通过使用CSS选择器来定位和选择Web页面上的元素的方法。在Web自动化测试中,CSS定位常用于定位和操作页面中的各种元素,例如按钮、文本框、链接等。
CSS定位使用CSS选择器来匹配符合特定条件的元素。CSS选择器是一种语法模式,它通过元素的属性、标签名、类名、ID等属性来选择元素。
具体就不演示了,我有一篇文章讲过CSS的相关语法.介绍
操作测试对象
前面讲到了不少知识都是定位元素,定位只是第一步,定位之后需要对这个元素进行操作。是鼠标点击
还是键盘输入,或者清除元素的内容,或者提交表单等。这个取决于定位元素需要进行的下一步操作。
我这里总结了我们常用的操作对象的方法.
- click点击对象
- send_keys在对象上模拟按键输入
- clear清除对象输入的文本内容
- submit提交
- text用于获取元素的文本信息
接下来给出实际的例子,来应用这几个方法.
private static void test03() throws InterruptedException {
ChromeOptions options = new ChromeOptions();
// 允许所有请求
options.addArguments("--remote-allow-origins=*");
WebDriver webDriver = new ChromeDriver(options);
webDriver.get("https://www.baidu.com/");
sleep(3000);
//找到百度搜索输入框,输入七龙珠
webDriver.findElement(By.cssSelector("#kw")).sendKeys("七龙珠");
//点击一下百度按钮
webDriver.findElement(By.cssSelector("#su")).click();
// 清空百度搜索输入框中的数据
webDriver.findElement(By.cssSelector("#kw")).clear();
}
这里特别对sumbit这个方法进行特别的说明:
如果点击的元素放在form标签中,此时使用submit实现的效果和click是一样的如果点击的元素放在非form标签中,此时使用submit报错
等待操作
Selenium提供了两种类型的等待操作:隐式等待(Implicit Waits)和显式等待(Explicit Waits)。
1.隐式等待(Implicit Waits):
隐式等待是设置在整个WebDriver实例的生命周期中,用于指定在查找元素时的最长等待时间。如果Selenium在指定的时间内找到了元素,它将立即继续执行后续的操作。如果在超时时间内未找到元素,它将抛出异常。
WebDriver driver = new ChromeDriver();
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
2.显式等待(Explicit Waits):
显式等待是通过编程方式指定等待条件,直到满足特定条件后再继续执行后续的操作。你可以设置等待的超时时间和轮询间隔,并指定等待条件(例如元素可见、元素存在等)。
WebDriverWait wait = new WebDriverWait(driver, 10);
WebElement element = wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("myElement")));
信息获取
信息获取,我们分为三个部分
url获取,title获取,某个属性值获取
private static void test05() {
ChromeOptions options = new ChromeOptions();
options.addArguments("--remote-allow-origins=*");
WebDriver webDriver = new ChromeDriver(options);
webDriver.get("https://www.baidu.com/");
String url = webDriver.getCurrentUrl();
String title = webDriver.getTitle();
if(url.equals("https://www.baidu.com/") && title.equals("百度一下,你就知道")) {
System.out.println("当前页面url:" + url + ",当前页面title:" + title);
System.out.println("测试通过");
} else {
System.out.println("测试不通过");
}
}
鼠标操作
鼠标操作分为以下几个方面
1.鼠标左键点击
2.鼠标右键点击
3.鼠标双击
具体大家看下面的代码
private static void test07() throws InterruptedException {
ChromeOptions options = new ChromeOptions();
//允许所有请求
options.addArguments("--remote-allow-origins=*");
WebDriver webDriver = new ChromeDriver(options);
webDriver.get("https://www.baidu.com/");
//点击百度导航栏上的图片按钮
//找到图片按钮
WebElement webElement=webDriver.findElement(By.cssSelector("#s-top-left > a:nth-child(6)"));
Actions actions = new Actions(webDriver);
sleep(3000);
//鼠标右键点击
actions.moveToElement(webElement).contextClick().perform();
//鼠标左键点击
actions.moveToElement(webElement).click().perform();
//鼠标双击
actions.moveToElement(webElement).doubleClick().perform();
}
键盘操作
大概介绍一些组合操作
send_keys(Keys.CONTROL,‘a’) #全选(Ctrl+A)
send_keys(Keys.CONTROL,‘c’) #复制(Ctrl+C)
send_keys(Keys.CONTROL,‘x’) #剪贴(Ctrl+X)
send_keys(Keys.CONTROL,‘v’) #粘贴(Ctrl+V)
代码如下:
private static void test11() throws InterruptedException {
WebDriver webDriver = new ChromeDriver();
// 打开百度首页
webDriver.get("https://wwww.baidu.com/");
// 搜索521
webDriver.findElement(By.cssSelector("#kw")).sendKeys("521");
// control+A
webDriver.findElement(By.cssSelector("#kw")).sendKeys(Keys.CONTROL, "A");
sleep(3000);
// control+X
webDriver.findElement(By.cssSelector("#kw")).sendKeys(Keys.CONTROL, "X");
sleep(3000);
// control+V
webDriver.findElement(By.cssSelector("#kw")).sendKeys(Keys.CONTROL, "V");
sleep(3000);
}
选项操作
选择操作说的是,我们经常遇到的操作,我这里会给出一定的例子,解释
例子一
<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8" />
<title>inner</title>
</head>
<body>
<div class="row-fluid">
<div class="span6 well">
<h3>inner</h3>
<iframe id="f2" src="https://www.baidu.com/"
width="700"height="500"></iframe>
<a href="javascript:alert('watir-webdriver better than selenium webdriver;')">click</a>
</div>
</div>
</body>
</html>
这里看似就是打开浏览器,按下F12,然后找到click的位置,再点击.但其实这样的操作是行不通的,不信的话,你们可以试试看.
我的方案如下:
在进行之前,我们要解释一个参数
switchTo().frame()方法用于切换到frame,然后才可以正常获取frame内的元素。这是因为:
默认情况下,WebDriver只能识别和操作页面的主DOM元素。frame被视为主DOM之外的子页面,WebDriver无法直接访问或定位frame内的元素。
所以,在操作frame内元素前,我们需要先使用switchTo().frame()方法切换到frame。此时WebDriver的作用域会从主DOM转到frame的DOM。然后就可以正常地获取和操作frame内的元素了。
切换到frame的基本语法是:
driver.switchTo().frame(frameElement);
private static void test08() {
WebDriver webDriver = new ChromeDriver();
webDriver.get("http://localhost:63342/SofeWareTest/src/main/page/inner.html?_ijt=ga8n81smfjjlv2l0aufov4aacf&_ij_reload=RELOAD_ON_SAVE");
//先使用switchTo().frame()方法切换到frame,然后正常获取元素。
webDriver.switchTo().frame("f1");
//找到元素实现点击
webDriver.findElement(By.cssSelector("body > div > div > a")).click();
}
例子二
实现这个页面的多个复选框点击
<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8" />
<title>Checkbox</title>
</head>
<body>
<h3>checkbox</h3>
<div class="well">
<form class="form-horizontal">
<div class="control-group">
<label class="control-label" for="c1">checkbox1</label>
<div class="controls">
<input type="checkbox" id="c1" />
</div>
</div>
<div class="control-group">
<label class="control-label" for="c2">checkbox2</label>
<div class="controls">
<input type="checkbox" id="c2" />
</div>
</div>
<div class="control-group">
<label class="control-label" for="c3">checkbox3</label>
<div class="controls">
<input type="checkbox" id="c3" />
</div>
</div>
<div class="control-group">
<label class="control-label" for="r">radio</label>
<div class="controls">
<input type="radio" id="r1" />
</div>
</div>
<div class="control-group">
<label class="control-label" for="r">radio</label>
<div class="controls">
<input type="radio" id="r2" />
</div>
</div>
</form>
</div>
</body>
</html>
代码如下:
private static void page01() {
WebDriver webDriver=new ChromeDriver();
webDriver.get("http://localhost:63342/SofeWareTest/src/main/page/test01.html?_ijt=h7dp7lq3pmit8q2glqh8agdld9&_ij_reload=RELOAD_ON_SAVE");
webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.DAYS);
List<WebElement> webElements =webDriver.findElements(By.cssSelector("input"));
for (int i=0;i<webElements.size();i++){
// 如果每个元素type值等于checkbox进行点击
// getAttribute获取页面上的元素属性值,里面的type是当前元素属性
if(webElements.get(i).getAttribute("type").equals("checkbox")){
webElements.get(i).click();
} else {
// 否则什么也不操作
;
}
}
}
例子三
我们要做的操作就是下拉菜单操作,大家想必都会遇到过
<html>
<body>
<select id="ShippingMethod" onchange="updateShipping(options[selectedIndex]);" name="ShippingMethod">
<option value="12.51">UPS Next Day Air ==> $12.51</option>
<option value="11.61">UPS Next Day Air Saver ==> $11.61</option>
<option value="10.69">UPS 3 Day Select ==> $10.69</option>
<option value="9.03">UPS 2nd Day Air ==> $9.03</option>
<option value="8.34">UPS Ground ==> $8.34</option>
<option value="9.25">USPS Priority Mail Insured ==> $9.25</option>
<option value="7.45">USPS Priority Mail ==> $7.45</option>
<option value="3.20" selected="">USPS First Class ==> $3.20</option>
</select>
</body>
</html>
代码如下:
private static void page03() {
WebDriver webDriver = new ChromeDriver();
webDriver.get("http://localhost:63342/SofeWareTest/src/main/page/test03.html?_ijt=nurtgo6e7vf9lecp8jvqlb9tfl&_ij_reload=RELOAD_ON_SAVE");
WebElement webElement = webDriver.findElement(By.cssSelector("#ShippingMethod"));
Select select = new Select(webElement);
select.selectByIndex(3);
// select.selectByValue("12.51");
}
例子四
碰到有些网页,它存在一些弹窗,会让你输入一些内容,我们针对这个弹窗进行一些操作
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<button onclick="Click()">这是一个弹窗</button>
</body>
<script type="text/javascript">
function Click() {
let name = prompt("请输入姓名:");
let parent = document.querySelector("body");
let child = document.createElement("div");
child.innerHTML = name;
parent.appendChild(child)
}
</script>
</html>
代码如下:
private static void page04() throws InterruptedException {
WebDriver webDriver = new ChromeDriver();
webDriver.get("http://localhost:63342/SofeWareTest/src/main/page/test04.html?_ijt=h9h618hcvg2s1mfkdbiudcq5c4&_ij_reload=RELOAD_ON_SAVE");
webDriver.findElement(By.cssSelector("button")).click();
sleep(3000);
// alert弹窗取消
webDriver.switchTo().alert().dismiss();
sleep(3000);
// 点击按钮
webDriver.findElement(By.cssSelector("button")).click();
// 在alert弹窗中输入卡卡罗特
webDriver.switchTo().alert().sendKeys("卡卡罗特");
// alert弹窗确认
sleep(3000);
webDriver.switchTo().alert().accept();
}
例子五
有时候网页会出现上传文件按钮操作
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<input type="file">
</body>
</html>
代码如下:
private static void page05() {
WebDriver webDriver = new ChromeDriver();
webDriver.get("http://localhost:63342/SofeWareTest/src/main/page/test05.html?_ijt=bhj6drp1unjqol4br0l4t8empg&_ij_reload=RELOAD_ON_SAVE");
webDriver.findElement(By.cssSelector("input")).sendKeys("D:\\untitled");
}
浏览器操作
关闭操作
在WebDriver中,关闭浏览器窗口有quit()和close()两个方法,其区别如下:
- quit()
- 关闭当前浏览器窗口并退出驱动程序。
- 结束与驱动程序的会话,释放与浏览器的连接。
- 如果还有其他打开的浏览器窗口,它们也将被关闭。
- 一旦调用quit(),该WebDriver实例不能再用于测试会话。
- close()
- 关闭当前浏览器窗口。
- 结束当前窗口与WebDriver之间的会话。
- 如果还有其他打开的浏览器窗口,它们不会被关闭。
- 调用close()后,该WebDriver实例仍然可用于当前测试会话的其他浏览器窗口。
如果只测试一个窗口,close()和quit()均可。
如果测试涉及多个窗口,建议使用quit()完全退出WebDriver,避免遗留窗口影响其他用例的执行。
在测试用例执行过程中可使用close()方法切换窗口,测试结束时使用quit()完全退出WebDriver。
private static void test10() throws InterruptedException {
WebDriver webDriver = new ChromeDriver();
webDriver.get("https://www.baidu.com/");
webDriver.findElement(By.cssSelector("#s-top-left > a:nth-child(1)")).click();
sleep(4000);
// webDriver.quit();
webDriver.close();
}
切换窗口操作
这里的切换窗口,值得是,我们在跳转到新窗口后,能够获取新窗口的元素,并进行相应的操作
private static void test09() throws InterruptedException {
WebDriver webDriver = new ChromeDriver();
webDriver.get("https://www.baidu.com/");
//点击新闻,此时浏览器出现俩个画面
webDriver.findElement(By.cssSelector("#s-top-left > a:nth-child(1)")).click();
sleep(3000);
// 通过getWindowHandles获取所有的窗口句柄
// 通过getWindowHandle获取的get打开的页面窗口句柄
System.out.println(webDriver.getWindowHandle());
Set<String> handles = webDriver.getWindowHandles();
String target_handle = "";
for(String handle:handles) {
target_handle = handle;
}
webDriver.switchTo().window(target_handle);
sleep(3000);
//在新页面进行输入和点击操作
webDriver.findElement(By.cssSelector("#ww")).sendKeys("新闻联播");
webDriver.findElement(By.cssSelector("#s_btn_wr")).click();
}
窗口句柄为WebDriver的窗口管理和切换提供了重要的技术支持。通过熟练掌握getWindowHandles()和switchTo().window()的用法,我们可以灵活地实现对多窗口的自动化测试。
截图操作
浏览器截图操作也是必备之需
private static void test10() throws InterruptedException, IOException {
// 创建ChromeDriver实例化对象
WebDriver webDriver = new ChromeDriver();
// 打开百度首页
webDriver.get("https://www.baidu.com/");
// 定位搜索输入框,并输入搜索内容
webDriver.findElement(By.cssSelector("#kw")).sendKeys("软件测试");
// 定位搜索按钮,并点击
webDriver.findElement(By.cssSelector("#su")).click();
// 等待3秒,等待搜索结果加载
sleep(3000);
// 由于WebDriver是接口,可以强制转型为TakesScreenshot接口
File file = ((TakesScreenshot)webDriver).getScreenshotAs(OutputType.FILE);
// 复制文件到指定目录并指定文件名
FileUtils.copyFile(file, new File("D://20230521jietu.png"));
}
六.需要用到的包
<!-- https://mvnrepository.com/artifact/org.seleniumhq.selenium/selenium-java -->
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>3.141.59</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.11.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-api -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.9.1</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<version>5.9.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-params -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<version>5.9.1</version>
</dependency>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-suite</artifactId>
<version>1.9.1</version>
<scope>test</scope>
</dependency>
<!-- 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>
<!-- 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>
<scope>test</scope>
</dependency>