JUnit 5和Selenium –改善项目配置

Selenium是一组支持浏览器自动化的工具和库,主要用于Web应用程序测试。 Selenium的组件之一是Selenium WebDriver,它提供客户端库,JSON有线协议(与浏览器驱动程序进行通信的协议)和浏览器驱动程序。 Selenium WebDriver的主要优点之一是,它受所有主要编程语言的支持,并且可以在所有主要操作系统上运行。

带有Selenium WebDriverJUnit 5的这一部分–教程中,您将了解JUnit 5的其他功能,这些功能将通过并行运行测试,配置测试顺序和创建参数化测试来帮助您减少测试的执行时间。

您还将学习如何利用Selenium Jupiter功能,例如通过系统属性进行测试执行配置,单个浏览器会话测试以加快测试执行速度或捕获测试中的屏幕截图。 最后,您将学习如何将AssertJ库添加到您的项目。

关于本教程

您正在阅读带有Selenium WebDriverJUnit 5的第三部分-教程

本教程中的所有文章:

  • 第1部分– 从头开始设置项目–使用JUnit 5和Jupiter Selenium进行Gradle
  • 第2部分– 使用Selenium内置的PageFactory实现Page Object Pattern
  • 第3部分– 改进项目配置–并行执行测试,测试执行顺序,参数化测试,AssertJ等

该教程的源代码可以在Github上找到

使用JUnit 5并行测试执行

JUnit 5带有内置的并行测试执行支持。

下面的命令将并行运行TodoMvcTests的测试方法:

 ./gradlew clean test --tests *TodoMvcTests -Djunit.jupiter.execution.parallel.enabled= true -Djunit.jupiter.execution.parallel.mode. default =concurrent 

构建成功,在执行过程中,您应该注意到两个Chrome浏览器实例正在运行。 在此运行中,所有测试的执行时间减少到10秒:

 > Task :test  pl.codeleak.demos.selenium.todomvc.TodoMvcTests > createsTodo() PASSED  pl.codeleak.demos.selenium.todomvc.TodoMvcTests > createsTodosWithSameName() PASSED  pl.codeleak.demos.selenium.todomvc.TodoMvcTests > togglesAllTodosCompleted() PASSED  pl.codeleak.demos.selenium.todomvc.TodoMvcTests > togglesTodoCompleted() PASSED  pl.codeleak.demos.selenium.todomvc.TodoMvcTests > clearsCompletedTodos() PASSED  pl.codeleak.demos.selenium.todomvc.TodoMvcTests > editsTodo() PASSED  pl.codeleak.demos.selenium.todomvc.TodoMvcTests > removesTodo() PASSED  BUILD SUCCESSFUL in 10s  4 actionable tasks: 4 executed 

提示:有关更多选项,请查阅文档: https : //junit.org/junit5/docs/current/user-guide/#writing-tests-parallel-execution

使用JUnit 5测试执行顺序

自动化测试应该能够独立运行并且没有特定的顺序,并且测试结果不应依赖于先前测试的结果。 但是在某些情况下可以证明测试执行的特定顺序。

默认情况下,在JUnit 5中,测试方法的执行在构建之间是可重复的,因此是确定性的,但是该算法是故意不明显的(作为库状态的作者)。 幸运的是,可以使用内置方法定购器或通过创建自定义定购器来调整执行顺序以适应我们的需求。 我们将使用@Order批注来提供测试方法的排序,并使用@TestMethodOrder注释类,以指示JUnit 5方法已排序。

 @ExtendWith (SeleniumExtension. class )  @SingleSession  @TestMethodOrder (MethodOrderer.OrderAnnotation. class )  @DisplayName ( "Managing Todos" @DisplayName "Managing Todos" )  class TodoMvcTests { @Test @Order ( 1 ) @DisplayName ( "Creates Todo with given name" ) void createsTodo() { } @Test @Order ( 2 ) @DisplayName ( "Creates Todos all with the same name" @DisplayName "Creates Todos all with the same name" ) void createsTodosWithSameName() { } // rest of the methods omitted for readability  } 

在本文中阅读有关JUnit 5中测试执行顺序的更多信息: https : //blog.codeleak.pl/2019/03/test-execution-order-in-junit-5.html

使用Selenium Jupiter的单个浏览器会话

您可能已经注意到,对于TodoMvcTests类中的每个测试, TodoMvcTests启动一个新的Chrome浏览器实例,并在每个测试之后将其关闭。 此行为导致整个套件的执行花费了相当多的时间(上一次执行需要27秒)。 Selenium Jupiter附带了一个方便的类级别注释,可以更改此行为。 @SingleSession注释会更改行为,以便在所有测试之前初始化浏览器实例一次,并在所有测试之后关闭浏览器实例。

要应用@SingleSession我们需要略微修改测试类,并将驱动程序对象注入到构造函数中,而不是注入到@BeforeEach方法中。 我们还需要注意每次测试的正确状态。 这可以通过清除@AfterEach方法中@AfterEach存储的本地存储来完成。 我还创建了一个现场driver ,该驱动driver保留了所有测试中使用的驱动程序对象实例。

我使用注入到@BeforeEach@AfterEach方法中的驱动程序测试了@SingleSession ,但似乎这没有按预期方式工作,并且每次执行新测试时,都会创建一个新的驱动程序实例。 我相信这是库的另一个设计缺陷。

 private final ChromeDriver driver;  public TodoMvcTests(ChromeDriver driver) { this .driver = driver; this .todoMvc = PageFactory.initElements(driver, TodoMvcPage. class ); this .todoMvc.navigateTo();  }  @AfterEach  void storageCleanup() { driver.getLocalStorage().clear();  } 

当我们执行测试时,我们可以观察到执行所有测试的时间大大减少了:

 ./gradlew clean test  > Task :test  pl.codeleak.demos.selenium.todomvc.TodoMvcTests > editsTodo() PASSED  pl.codeleak.demos.selenium.todomvc.TodoMvcTests > togglesTodoCompleted() PASSED  pl.codeleak.demos.selenium.todomvc.TodoMvcTests > createsTodo() PASSED  pl.codeleak.demos.selenium.todomvc.TodoMvcTests > removesTodo() PASSED  pl.codeleak.demos.selenium.todomvc.TodoMvcTests > togglesAllTodosCompleted() PASSED  pl.codeleak.demos.selenium.todomvc.TodoMvcTests > createsTodosWithSameName() PASSED  pl.codeleak.demos.selenium.todomvc.TodoMvcTests > clearsCompletedTodos() PASSED  pl.codeleak.demos.selenium.todomvc.SeleniumTest > projectIsConfigured(ChromeDriver) PASSED  BUILD SUCCESSFUL in 9s  3 actionable tasks: 3 executed 

提示:如果您希望从选定的类中运行测试,则可以使用Gradle测试任务随附的测试过滤。 例如,此命令将仅运行TodoMvcTests类中的测试: ./gradlew clean test --tests *.todomvc.TodoMvcTests

并行执行单个浏览器会话测试

请注意,如果您现在尝试使用JUnit 5并行性并行执行测试,则测试将失败。 在并行执行中,每个方法都需要单独的驱动程序实例,并启用@SingleSession我们为所有测试共享一个实例。 为了解决这个问题,我们需要运行测试配置并行执行,以便顶级类并行运行,但方法在同一线程中。

只需复制TodoMvcTests类,然后尝试以下命令:

 ./gradlew clean test --tests *TodoMvcTests -Djunit.jupiter.execution.parallel.enabled= true -Djunit.jupiter.execution.parallel.mode. default =same_thread -Djunit.jupiter.execution.parallel.mode.classes. default =concurrent 

在执行过程中,您应该看到3个浏览器正在运行并在终端中输出,类似于以下内容:

 <===========--> 87 % EXECUTING [3s]  > :test > 0 tests completed  > :test > Executing test pl.codeleak.demos.selenium.todomvc.MoreTodoMvcTests  > :test > Executing test pl.codeleak.demos.selenium.todomvc.EvenMoreTodoMvcTests  > :test > Executing test pl.codeleak.demos.selenium.todomvc.TodoMvcTests 

Selenium Jupiter的通用驱动程序配置

在当前测试中,我们将ChromeDriver直接注入测试类。 但是在某些情况下,我们希望对注入的驱动程序有更多的控制,而我们宁愿注入WebDriver(接口)并稍后决定应该注入哪个驱动程序实例。 我们还需要更改storageCleanup()方法,因为通用WebDriver不提供直接的localStorage访问:

 public TodoMvcTests(WebDriver driver) { this .driver = driver; this .todoMvc = PageFactory.initElements(driver, TodoMvcPage. class ); this .todoMvc.navigateTo();  }  @AfterEach  void storageCleanup() { ((JavascriptExecutor) driver).executeScript( "window.localStorage.clear()" );  } 

现在,要在运行时更改浏览器类型,我们需要调整sel.jup.default.browser config属性。

配置JUnit 5和Selenium Jupiter的常用方法之一是通过Java系统属性。 可以使用属性文件以编程方式完成此操作,也可以使用-D开关将属性直接传递给JVM。 为了确保在执行Gradle时传递给JVM的属性在测试中可用,我们需要修改build.gradle ,如下所示:

 test { // Make system properties available in tests systemProperties System.getProperties() useJUnitPlatform() testLogging { events "passed" , "skipped" , "failed" }  } 

到目前为止,当您运行./gradlew clean test -Dprop=value类的命令时,该属性prop将在测试中可用。

通过上述更改,我们可以选择浏览器类型来运行测试:

 ./gradlew clean test --tests *TodoMvcTests -Dsel.jup. default .browser=firefox 

使用Selenium Jupiter保存屏幕截图

Selenium Jupiter允许在测试结束时保存屏幕截图-始终或仅在失败时保存。 您还可以自定义输出目录和格式。

 ./gradlew clean test --tests *TodoMvcTests -Dsel.jup. default .browser=firefox -Dsel.jup.screenshot.at.the.end.of.tests= true -Dsel.jup.screenshot.format=png -Dsel.jup.output.folder=/tmp 

提示:有关更多选项,请查阅文档: https : //bonigarcia.github.io/selenium-jupiter/#screenshots

使用JUnit 5进行参数化测试

参数化单元测试的总体思路是针对不同的测试数据运行相同的测试方法。 要在JUnit 5中创建参数化测试,请使用@ParameterizedTest注释测试方法,并提供该测试方法的参数源。 有几种可用的参数来源,包括:

  • @ValueSource –提供对文字值数组(即短裤,整数,字符串等)的访问。
  • @MethodSource –提供对从工厂方法返回的值的访问
  • @CsvSource –从一个或多个提供的CSV行中读取逗号分隔值(CSV)
  • @CsvFileSource –用于加载逗号分隔值(CSV)文件

在下一个示例中,我们将使用存储在src/test/resources目录中的以下CSV:

 todo;done  Buy the milk; false  Clean up the room; true  Read the book; false 

为了在测试中使用上述CSV文件,我们需要使用@ParameterizedTest批注(而不是@Test )对测试进行批注,后跟指向文件的@CsvFileSource批注:

 @ParameterizedTest  @CsvFileSource (resources = "/todos.csv" , numLinesToSkip = 1 , delimiter = ';' )  @DisplayName ( "Creates Todo with given name" )  void createsTodo(String todo) { todoMvc.createTodo(todo); assertSingleTodoShown(todo);  } 

CSV文件中的每个记录都有两个字段: namedone 。 在上述测试中,仅使用待办事项的名称。 但是我们当然可以使测试复杂一点,并同时使用这两个属性:

 @ParameterizedTest (name = "{index} - {0}, done = {1}" )  @CsvFileSource (resources = "/todos.csv" , numLinesToSkip = 1 , delimiter = ';' )  @DisplayName ( "Creates and optionally removes Todo with given name" )  void createsAndRemovesTodo(String todo, done) { boolean done) { todoMvc.createTodo(todo); assertSingleTodoShown(todo); todoMvc.showActive(); assertSingleTodoShown(todo); if (done) { todoMvc.completeTodo(todo); assertNoTodoShown(todo); todoMvc.showCompleted(); assertSingleTodoShown(todo); } todoMvc.removeTodo(todo); assertNoTodoShown(todo);  } 

请注意,同一测试类别/

了解更多关于这篇文章中参数的测试: https://blog.codeleak.pl/2017/06/cleaner-parameterized-tests-with-junit-5.html也经历了JUnit 5文档: https://开头的JUnit .org / junit5 / docs / current / user-guide /#writing-tests-parameterized-tests

使用AssertJ更好的断言

JUnit 5具有许多内置的断言,但是当实际工作开始时,您可能需要的远远超出JUnit 5所能提供的。 在这种情况下,我建议使用AssertJ库。 AssertJ AssertJ是一个Java库,提供了一组丰富的断言,真正有用的错误消息,提高了测试代码的可读性,并且设计为在您喜欢的IDE中非常容易使用。

AssertJ的一些功能:

  • 对许多Java类型的流利断言,包括日期,集合,文件等。
  • SoftAssertions(类似于JUnit 5的assertAll)
  • 复杂领域比较
  • 可以轻松扩展–自定义条件和自定义断言

要在项目中使用AssertJ,我们需要向build.gradle添加一个依赖build.gradle

 testCompile( 'org.assertj:assertj-core:3.13.2' ) 

首先,我们需要静态导入org.assertj.core.api.Assertions.*并使用带有assertThat方法的代码完成: assertThat(objectUnderTest).

例如,您将编写assertThat(todoMvc.getTodosLeft()).isEqualTo(3); 使用AssertJ而不是assertEquals(3, todoMvc.getTodosLeft()); 在普通的JUnit 5中或使用assertThat(todoMvc.todoExists(readTheBook)).isTrue()而不是assertTrue(todoMvc.todoExists(readTheBook))

使用复杂类型甚至更好:

 todoMvc.createTodos(buyTheMilk, cleanupTheRoom, readTheBook);  assertThat(todoMvc.getTodos()) .hasSize( 3 ) .containsSequence(buyTheMilk, cleanupTheRoom, readTheBook); 

访问官方文档以了解有关AssertJ的更多信息: https ://assertj.github.io/doc/

提示:阅读有关将AssertJ与JUnit 5集成的更多信息: https ://blog.codeleak.pl/2017/11/junit-5-meets-assertj.html

摘要

在本文中,我介绍了如何利用JUnit 5的内置功能来提高项目配置的速度,但不仅限于速度。 您还了解了如何利用某些Selenium Jupiter功能来改善项目。

JUnit 5和Selenium Jupiter似乎已经提供了更多的功能。 查看两个项目文档,并找出对当前或将来的项目有用的其他内容:

  • https://bonigarcia.github.io/selenium-jupiter/
  • https://junit.org/junit5/

翻译自: https://www.javacodegeeks.com/2019/12/junit-5-and-selenium-improving-project-configuration.html

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

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

相关文章

linux shc shell脚本_详解shell脚本加密解密软件—gzese和shc

概述以我个人的需求为例&#xff0c;有时写一个脚本需要传密码&#xff0c;如果直接把密码写在脚本里会存在安全问题&#xff0c;一般是把密码写在脚本里&#xff0c;作为参数传给脚本&#xff0c;而保存密码的脚本&#xff0c;使用某种手段加密&#xff0c;令其不可读但是可执…

python3 for计数_python怎么实现计数?

python中实现计数的一般方法&#xff1a;1、使用字典解决(dict)字典计数是最常用的计数方法&#xff0c;逐个遍历数据结构中元素&#xff0c;将元素作为键&#xff0c;元素个数作为值进行统计&#xff0c;依次加入字典中。实例演示test_lst [a, b, c, d, e, f, g, a, f, s, b,…

linux 查看主板sn_如何在 Linux 上查找硬件规格

在 Linux 系统上有许多工具可用于查找硬件规格。-- Sk(作者)在 Linux 系统上有许多工具可用于查找硬件规格。在这里&#xff0c;我列出了四种最常用的工具&#xff0c;可以获取 Linux 系统的几乎所有硬件(和软件)细节。好在是这些工具在某些 Linux 发行版上默认预装。我在 Ubun…

输入流输出流是以内存为标准_构建用于测试的超大内存输入流

输入流输出流是以内存为标准由于某种原因&#xff0c;我需要非常大的&#xff0c;甚至可能是无限的InputStream &#xff0c;它会反复地反复返回相同的byte[] 。 这样&#xff0c;我可以通过重复小样本来产生疯狂的大数据流。 可以在Guava中找到类似的功能&#xff1a; Iterabl…

laravel 分词搜索匹配度_【地名地址】面向智慧城市的高精度地名地址匹配方法...

点击上方蓝字关注我们↑↑↑↑原 文 摘 要针对智慧城市建设中各种业务数据对地名地址匹配准确度和效率不高的问题&#xff0c;本文提出一种面向智慧城市的高精度地名地址匹配方法。该方法在基于中文分词的地名地址匹配技术框架下&#xff0c;综合利用精细化地名地址库构建、地名…

使用通用mapper实现条件查询_使用dsum轻松搞定多条件查询,学会它,再也想用sumifs了...

在excel中条件求和想必大家都不陌生&#xff0c;这个可以说是我们工作中经常遇到的问题&#xff0c;常见的条件求和函数有sumif以及sumifs&#xff0c;但是还有一个更加强但知道的人却非常少的函数&#xff0c;他就是dsum函数&#xff0c;dsum相交于sumif以及sumifs函数理解起来…

输入文字自动生成图片_批量生成变化的图片文字海报

最近“双十一”活动大家已经进入了鸡血状态&#xff0c;运营的小伙伴给设计出了个难题&#xff0c;搞的设计小伙伴们进入了癫狂模式。本着工具提升效率的原则&#xff0c;我又开始去研究如何批量修改图片内容了&#xff0c;小小的成果和大家分享一下。提出问题为每一位支付了定…

生成私钥 p q rsa_【安全】理解 RSA 算法

Public-key Crytography简介Public-key cryptography (公开密钥加密) 又称 asymmetric cryptography (非对称加密)&#xff0c;即存在两把不同的密钥&#xff0c;分别称为公钥 Pu 和私钥 Pr&#xff0c;公钥通常用来加密明文 M&#xff0c;只有私钥才能解密密文 C&#xff0c;如…

Java:如何创建轻量级数据库微服务

基于云的Java数据库应用程序的数量每分钟都在增加。 许多组织部署了数百甚至数千个微服务实例。 但是&#xff0c;相对于运行时环境&#xff0c;大多数应用程序会带来惊人数量的不必要开销。 反过来&#xff0c;这会使应用程序运行更慢&#xff0c;运行成本更高。 在本文中&am…

垃圾分类毕设java程序_垃圾“拍一拍”,分类不用愁!生活垃圾分类查询小程序上线啦...

垃圾种类太多&#xff1f;分类容易搞混&#xff1f;乐清人 注意啦&#xff0c;拿起手机就能查&#xff01;11月6日&#xff0c;生活垃圾分类查询系统登陆乐清市综合行政执法局官方微信公众号&#xff0c;输入垃圾名称即可快速了解垃圾所属哪一类&#xff0c;还有拍照识别查询&a…

带有Prometheus的弹簧靴和千分尺第5部分:旋转Prometheus

以前&#xff0c;我们获得了Spring Boot Application适配器&#xff0c;以便为Prometheus公开端点。 该博客将重点介绍如何设置和配置Prometheus&#xff0c;以便为Spring Boot端点提供服务器。 因此&#xff0c;让我们开始使用docker来启动Prometheus服务器。 在继续进行Pr…

允许跨域访问_PHP设置多域名允许跨域访问

php中文网最新课程 每日17点准时技术干货分享 针对 PHP 语言设置多域名允许跨域访问 服务器变量: 服务器变量存储在 $_SERVER 数组中,在这个数组中有一个特殊的键值:HTTP_ORIGIN。 这个键只在跨域的时候才会存在值,同源时为空字符串 响应头设置允许某域名访问:access-cont…

python函数的作用降低编程复杂度_Python函数式编程

lambda本文将介绍Python中函数式编程的特性。在对函数式编程的概念有了了解后&#xff0c;本文会介绍iterators和generators等语言特性&#xff0c;还有itertools和functools等相关的库。函数式编程本章节将会介绍函数式编程的一些基本概念&#xff1b;如果只是对Python的语言特…

Apache Camel 3.1 –即将推出更多骆驼核心优化

希望一切都很好&#xff0c;您可以安全进入2020年。 Camel团队已经在忙于开发下一个Camel 3.1版本。 目标之一是继续优化骆驼核心&#xff0c;这一次我们花了一些时间来寻找路由引擎中的一些热点。 我们所研究的方面之一也是在Camel路由的每个消息中发生的对象分配。 JVM本身…

判断字符为空_算法题:字符串转换整数 (atoi)

题目描述题解分析他人更优解一、题目描述二、题解import math class Solution:def myAtoi(self,str):str str.strip() #去除字符串两边的空格if len(str) 0: return 0 #如果字符串为空返回0if not str[0].isdigit() and str[0] ! - and str[0] ! : #判断第一个字符是…

python 3.5.2设计页面_怎么解决win10系统搭建Python 3.5.2开发环境的处理方案

今天小编告诉大家如何对win10系统搭建Python 3.5.2开发环境进行设置&#xff0c;可能很多用户都不知道怎么对win10系统搭建Python 3.5.2开发环境进行设置&#xff0c;但当我们遇到对win10系统搭建Python 3.5.2开发环境进行设置的问题怎么办呢&#xff1f;遇到这种情况不要着急&…

Eclipse系列的隐藏宝藏-2019年版

Eclipse Collections是一个开放源代码Java Collections框架。 在此博客中&#xff0c;我将演示该框架的五个鲜为人知的功能。 我在去年的Java Advent Calendar中发布了一个类似的博客 。 请参阅博客末尾的资源以获取有关该框架的更多信息。 1. countBy() &#xff1a;要查找特…

mongodb一致性协议_mongo的怎么保持事物的一致性-问答-阿里云开发者社区-阿里云...

http://docs.mongoing.com/manual-zh/tutorial/perform-two-phase-commits.html要么操作全都执行&#xff0c;要么都不执行&#xff0c;不能执行一半&#xff0c;改了几条数据了&#xff0c;看哎哟好像不对&#xff0c;那扔着吧。Consistency 在数据库领域的意思跟在分布式系统…

picturectrl控件中加载图片并显示_在 CRA 中使用 webp 图片提升加载性能

webp 是 google 提倡的一种新的 image 格式&#xff0c;意在为 web 提供体积更小的图片格式。通常情况下&#xff0c;无损压缩可以减小 25%-35% 的体积&#xff08;有例外情况&#xff0c;反而会增大体积&#xff0c;但是是因为转换图片格式不兼容引起的&#xff09;&#xff0…

怎么打开网卡rss_RSS 进阶篇:Huginn - 真·为任意网页定制 RSS 源(PhantomJs 抓取)...

定制网页RSS源主要有FEED43和Huginn两种方法。FEED43&#xff1a;简单免费&#xff0c;六小时抓取一次&#xff0c;每次抓取20条静态页面。使用攻略- RSS 入门篇&#xff1a;FEED43&FeedEx-为静态网页定制 RSS 源2. Huginn&#xff1a;自由度高&#xff0c;可设定抓取频率、…