JUnit 5和Selenium基础(三)
在这一部分教程中,将介绍JUnit 5的其他功能,这些功能将通过并行运行测试,配置测试顺序和创建参数化测试来帮助减少测试的执行时间。还将介绍如何利用Selenium Jupiter功能,例如通过系统属性进行测试执行配置,单个浏览器会话测试以加快测试执行速度或捕获测试中的屏幕截图,AssertJ库的基本Demo。
使用JUnit 5并行测试执行
JUnit 5带有内置的并行测试执行支持。下面的命令将并行运行TodoMvcTests
的测试方法:
./gradlew clean test --tests *TodoMvcTests -Djunit.jupiter.execution.parallel.enabled=true -Djunit.jupiter.execution.parallel.mode.default=concurrent
构建成功,在执行过程中,注意到两个Chrome浏览器实例正在运行。在此运行中,所有测试的执行时间减少到原来的几分之一:
> Task :test
demos.selenium.todomvc.TodoMvcTests > createsTodo() PASSED
demos.selenium.todomvc.TodoMvcTests > createsTodosWithSameName() PASSED
demos.selenium.todomvc.TodoMvcTests > togglesAllTodosCompleted() PASSED
demos.selenium.todomvc.TodoMvcTests > togglesTodoCompleted() PASSED
demos.selenium.todomvc.TodoMvcTests > clearsCompletedTodos() PASSED
demos.selenium.todomvc.TodoMvcTests > editsTodo() PASSED
demos.selenium.todomvc.TodoMvcTests > removesTodo() PASSED
BUILD SUCCESSFUL in 10s
4 actionable tasks: 4 executed
使用JUnit 5测试执行顺序
一般来讲,自动化测试应该能够独立运行并且没有特定的顺序,并且测试结果不应依赖于先前测试的结果。但是在某些情况下测试执行需要依赖特定顺序。
默认情况下,在JUnit 5中,测试方法的执行在构建之间是无序的,因此非确定性的。但是可以使用内置方法定购器或通过创建自定义定购器来调整执行顺序以满足测试的需求。我们将使用@Order
批注来提供测试方法的排序,并使用注释类,@TestMethodOrder
以指示JUnit 5
方法已排序。
@ExtendWith(SeleniumExtension.class)
@SingleSession
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
@DisplayName("Managing Todos")
class TodoMvcTests {
@Test
@Order(1)
@DisplayName("test001")
void createsTodo() {
}
@Test
@Order(2)
@DisplayName("test002")
void createsTodosWithSameName() {
}
}
使用Selenium Jupiter的单个浏览器会话
对于TodoMvcTests
类中的每个测试,都会启动一个新的Chrome
浏览器实例,并在每个测试之后将其关闭。此行为导致整个套件的执行花费了相当多的时间。Selenium Jupiter
附带了一个简单的类级别注释,可以修改这项功能。@SingleSession
批注会更改行为,以便在所有测试之前初始化浏览器实例一次,并在所有测试之后关闭浏览器实例。
要应用@SingleSession
需要稍微修改测试类,然后将驱动程序对象注入构造函数中而不是@BeforeEach
方法中。我们还需要注意每次测试的正确状态。这可以通过清除@AfterEach
方法中存储待办事项的本地存储来完成。我还创建了一个字段driver
,该字段保留所有测试中使用的驱动程序对象实例。
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
demos.selenium.todomvc.TodoMvcTests > editsTodo() PASSED
demos.selenium.todomvc.TodoMvcTests > togglesTodoCompleted() PASSED
demos.selenium.todomvc.TodoMvcTests > createsTodo() PASSED
demos.selenium.todomvc.TodoMvcTests > removesTodo() PASSED
demos.selenium.todomvc.TodoMvcTests > togglesAllTodosCompleted() PASSED
demos.selenium.todomvc.TodoMvcTests > createsTodosWithSameName() PASSED
demos.selenium.todomvc.TodoMvcTests > clearsCompletedTodos() PASSED
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
在执行过程中,应该看到正在运行并在终端中输出以下内容:
<===========--> 87% EXECUTING [3s]
> :test > 0 tests completed
> :test > Executing test demos.selenium.todomvc.MoreTodoMvcTests
> :test > Executing test demos.selenium.todomvc.EvenMoreTodoMvcTests
> :test > Executing test 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.browserconfig
属性。
配置JUnit 5
和Selenium Jupiter
的常用方法之一是通过Java系统属性。可以使用属性文件以编程方式完成此操作,也可以使用-Dswitch
将属性直接传递给JVM 。为了确保在执行Gradle
时传递给JVM的属性在测试中可用,我们需要进行build.gradle
如下修改:
test {
systemProperties System.getProperties()
useJUnitPlatform()
testLogging {
events "passed", "skipped", "failed"
}
}
当运行命令时./gradlew clean test -Dprop=value
,该属性将在测试中可用。通过上述更改,我们可以选择浏览器类型来运行测试:
./gradlew clean test --tests *TodoMvcTests -Dsel.jup.default.browser=firefox
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
使用JUnit 5进行参数化测试
参数化单元测试的总体思路是针对不同的测试数据运行相同的测试方法。要在JUnit 5中创建参数化测试,请使用注释测试方法,@ParameterizedTest并提供该测试方法的参数源。有几种可用的参数来源,包括:
- @ValueSource –提供对文字值数组(例如,int,字符串等)的访问。
- @MethodSource –提供对从工厂方法返回的值的访问
- @CsvSource –从一个或多个提供的CSV行中读取逗号分隔值(CSV)
- @CsvFileSource –用于加载逗号分隔值(CSV)文件
为了在测试中使用上述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格式存储在src/test/resources
目录中:
todo;done
Buy the milk;false
Clean up the room;true
Read the book;false
CSV文件中的每个记录都有两个字段:name
和done
。在上述测试中,仅使用待办事项的名称。但是我们当然可以使测试复杂一点,并同时使用这两个属性:
@ParameterizedTest(name = "{index} - {0}, done = {1}" )
@CsvFileSource(resources = "/todos.csv", numLinesToSkip = 1, delimiter = ';')
@DisplayName("test003")
void createsAndRemovesTodo(String todo, 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);
}
使用AssertJ更好的断言
JUnit 5
具有许多内置的断言,在实际工作中,可能需要的超出JUnit 5
所能提供的。在这种情况下,建议使用AssertJ库。AssertJ
是一个Java库,提供了一组丰富的断言,真正有用的错误消息,提高了测试代码的可读性,并且设计为IDE中容易使用。
AssertJ的一些功能:
- 对许多Java类型的流利断言,包括日期,集合,文件等。
- SoftAssertions(类似于JUnit 5的assertAll)
- 复杂领域比较
- 可以轻松扩展–自定义条件和自定义断言
要在项目中使用AssertJ,我们需要向中添加单个依赖项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);
- 郑重声明:文章首发于公众号“FunTester”,禁止第三方(腾讯云除外)转载、发表。
技术类文章精选
- java一行代码打印心形
- Linux性能监控软件netdata中文汉化版
- 性能测试框架第二版
- 如何在Linux命令行界面愉快进行性能测试
- 图解HTTP脑图
- 将swagger文档自动变成测试代码
- 基于java的直线型接口测试框架初探
- Selenium 4.0 Alpha更新日志
- Selenium 4.0 Alpha更新实践
- 如何统一接口测试的功能、自动化和性能测试用例
非技术文章精选
- 为什么选择软件测试作为职业道路?
- 写给所有人的编程思维
- 成为自动化测试的7种技能
- 如何在DevOps引入自动化测试
- Web端自动化测试失败原因汇总
- 如何在DevOps引入自动化测试
- 测试人员常用借口
- API测试基础
- API自动化测试指南
- 未来的QA测试工程师
JUnit 5和Selenium基础(三)的更多相关文章
- JUnit 5和Selenium基础(一)
Gradle.JUnit 5和Jupiter Selenium Selenium是一组支持浏览器自动化的工具,主要用于Web应用程序测试.Selenium的组件之一是Selenium WebDrive ...
- JUnit 5和Selenium基础(二)
使用Selenium内置的PageFactory实现页面对象模式 在这一部分中,将通过Selenium的内置PageFactory支持类来介绍Page Object模式的实现.PageFactory提 ...
- jdbc基础 (三) 大文本、二进制数据处理
LOB (Large Objects) 分为:CLOB和BLOB,即大文本和大二进制数据 CLOB:用于存储大文本 BLOB:用于存储二进制数据,例如图像.声音.二进制文件 在mysql中,只有B ...
- web 自动化测试 selenium基础到应用(目录)
第一章 自动化测试前提及整体介绍 1-1功能测试和自动化测试的区别 1-2自动化测试流程有哪些 1-3自动化测试用例和手工用例的区别 1-4 自动化测试用例编写 1-5 selenium的优势以及 ...
- selenium基础-图形验证码
selenium基础-图形验证码 一.图形验证码作用 设计的初衷其实就是为了防自动化,防止一些人利用自动工具恶意攻击网站 二.图形验证码是由客户端生成还是由服务器端生成的? 图形验证码是由服务器端生成 ...
- Python+Selenium基础入门及实践
Python+Selenium基础入门及实践 32018.08.29 11:21:52字数 3220阅读 23422 一.Selenium+Python环境搭建及配置 1.1 selenium 介绍 ...
- 「译」JUnit 5 系列:基础入门
原文地址:http://blog.codefx.org/libraries/junit-5-basics/ 原文日期:25, Feb, 2016 译文首发:Linesh 的博客:JUnit 5 系列: ...
- Python全栈开发【基础三】
Python全栈开发[基础三] 本节内容: 函数(全局与局部变量) 递归 内置函数 函数 一.定义和使用 函数最重要的是减少代码的重用性和增强代码可读性 def 函数名(参数): ... 函数体 . ...
- Bootstrap <基础三十二>模态框(Modal)插件
模态框(Modal)是覆盖在父窗体上的子窗体.通常,目的是显示来自一个单独的源的内容,可以在不离开父窗体的情况下有一些互动.子窗体可提供信息.交互等. 如果您想要单独引用该插件的功能,那么您需要引用 ...
随机推荐
- Python--day60--一个简单(不完整)的web框架
- 4-2 setting中一定要将ROBOTSTXT_OBEY = False的注释去掉
# Obey robots.txt rules##默认遵循robots协议的,默认去读取每个网站上的robots协议ROBOTSTXT_OBEY = False
- Vue 各个阶段生命周期函数
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- Vue 项目构建完成 ----发布项目
发布项目 cmd 命令行 npm run build 执行打包文件 完成后就会有 3 个文件夹 分别是: 文件夹 :build config dist in ...
- Jmeter完整Demo
1:创建一个线程组 2:添加一个cookie管理器 3:设置你的信息头管理器:application/json;text/plain;charset=UTF-8 44 4:添加一个用户参数,做全局变量 ...
- C# 在基类定义好方法让子类继承接口就能实现
在 C# 里面,接口的定义只需要类里面存在和接口声明相同的方法或属性就可以,而存在的方法或属性是在子类定义的还是基类里面定义的都无所谓.也就是在基类里面写好了方法,但不继承接口,等子类继承接口的时候就 ...
- webpack4.0基本配置,超简单!
最近复习了一下webpack,使用的是4.0版本. 下图是基本目录结构,最后留有代码地址,有兴趣可以去看看. 直接上代码(依赖未完全使用): 项目的所有依赖都可以安装,每个都有详细的注释.] cons ...
- POJ - 3415 Common Substrings (后缀数组)
A substring of a string T is defined as: T( i, k)= TiTi +1... Ti+k -1, 1≤ i≤ i+k-1≤| T|. Given two s ...
- CentOS 7 修改root密码
1.开机,在启动菜单上选择CentOS Linux (3.10**.**.x86**) 7 (Core) 按下e,进入编辑模式2.将光标一直移动到 LANG=en_US.UTF-8 后面(如果找不到, ...
- JMeter数据库测试计划
在系统上安装数据库服务器之后. 按着这些次序: 创建名为testdb的数据库. 创建表 - tb_user. 将记录插入到tb_user表中. 下图显示了创建的数据库及其记录. 注意:您需要将相应的J ...