视觉测试工具箱
bigegpt 2024-11-20 12:38 5 浏览
视觉回归测试最常见的情况是使用基线图像进行测试。然而,视觉测试的不同方面也值得讨论。我们将介绍模板匹配(使用OpenCV)、布局测试(使用Galen)和OCR(使用Tesseract),并展示如何将这些工具无缝集成到现有的Appium和Selenium测试中。
我们使用Java(以及OpenCV和Tesseract的Java包装器),但类似的解决方案也可以通过其他技术堆栈实现。
这篇文章是2020年9月在新加坡的Taqelah和2020年Selenium会议期间(以较短的形式)发表的快速演讲的配套文章。有关完整功能的演示和更多详细信息,请参阅 http://www.justtestlah.qa/
我希望这个总结能帮助你选择对你的用例最有影响的工具,并给你一些关于如何将它们集成到你自己的工具箱中的想法。
模板匹配
模板匹配的任务是在当前屏幕上找到给定的图像(模板)。
Waldo在哪里?
对于移动测试,Appium在其1.9版本中以图像定位器策略的形式添加了此功能。(更多信息可以在文档和早期教程中找到)其思想是将图像的Base64编码字符串表示传递给WebDriver。
- 早期教程:https://appiumpro.com/editions/32-finding-elements-by-image-part-1
使用图像定位器(image locator),你可以像任何其他WebElement一样与结果元素交互。例如:
WebElement element =
driver.findElementByImage(base64EncodedImageFile);
element.click();
或
By image = MobileBy.image(base64EncodedImageFile);
new WebDriverWait(driver, 10).until(ExpectedConditions.presenceOfElementLocated(image)).click();
开发人员采用的方法是将功能添加到Appium服务器的一部分,并使用OpenCV(这将成为运行Appium服务器的实例的依赖项)来增强实际的图像识别能力。
有趣的是,客户端与服务器之间的流程如下所示:
- 从Appium服务器请求截图。
- 将屏幕截图和模板都发送到Appium服务器进行匹配。
这感觉并不完美,尤其是如果我们想在同一个屏幕上匹配多个模板。
当我在2018年首次实现模板匹配时(当时还不知道Appium团队已经在开发模板匹配),我也选择了OpenCV,而是在客户端运行了它。使用OpenCV Java包装器,我的代码要点如下所示:
Mat result = new Mat(resultRows, resultCols, CvType.CV_32FC1);
Imgproc.matchTemplate(image, templ, result, Imgproc.TM_CCOEFF_NORMED);
MinMaxLocResult match = Core.minMaxLoc(result);
if (match.maxVal >= threshold) {
// found
}
这种方法不需要向上述Appium服务器发出额外的请求。实际上,除了屏幕截图的功能外,它不需要WebDriver的任何功能。它还可以与Selenium和Appium一起使用。也就是说,这也增加了对OpenCV的依赖,这次是对运行测试执行的实例的依赖。
我将以上两种方法(客户端和服务器端执行)都包装到TemplateMatcher接口中,以展示其用法(将其视为PoC)。
你可以在JustTestLah中找到更多详细信息和示例!
- JTL测试框架:https://justtestlah.qa/#template-matching
布局测试
另一种视觉测试类型涉及验证页面或屏幕的布局。你可以通过图像比较来做到这一点,图像比较也会隐式检查布局。一种更简单的方法是使用像Galen这样的专用布局测试工具(在我看来,这是最被低估的UI测试框架之一)。
Galen使用每个屏幕的规范来定义屏幕上的所有(重要)元素及其大小以及它们之间的绝对或相对位置。
让我们以Google搜索页为例:
我们可以使用以下规范表示它:
SEARCH_FIELD:
below LOGO
centered horizontally inside viewport
visible
LOGO:
above SEARCH_FIELD
centered horizontally inside viewport
width < 100% of SEARCH_FIELD/width
visible
SEARCH_BUTTON:
near LUCKY_BUTTON 20px left
visible
注意,上面使用的是JustTestLah!框架的语法(通过在页面对象的YAML文件中定义的唯一键引用UI元素)。在纯Galen中,这些需要在spec文件的顶部定义:
@objects
LOGO id hplogo
SEARCH_FIELD css input[name=q]
...
有多种执行这些检查的方法。我更喜欢将verify方法作为BasePage抽象类的一部分:
private T verify() {
String baseName = this.getClass().getSimpleName();
String baseFolder = this.getClass().getPackage().getName().replaceAll("\\.", File.separator);
String specPath = baseFolder
+ File.separator
+ configuration.getPlatform()
+ File.separator
+ baseName
+ ".spec";
galen.checkLayout(specPath, locators);
return (T) this;
}
这样,每当我们第一次与屏幕交互时,我们都可以轻松地从测试中调用验证(顺便说一句,我使用类似的方法来集成Applitools进行视觉测试):
public class GoogleSteps extends BaseSteps {
private GooglePage google;
@Given("I am on the homepage")
public void homepage() {
google.verify().someAction().nextAction();
}
}
光学字符识别(OCR)
视觉断言的另一种形式是光学字符识别,其首字母缩写为OCR。每当由于某种原因将文本渲染为图像并且无法使用标准测试工具进行验证时,此功能将非常有用。
对于那些使用Selenium进行Web抓取而不是进行测试的用户来说,这可能也很有趣,因为这是网站开发人员采取的反措施之一,以使其变得更加困难。
我们使用Tesseract(一种最初由HP在1980年代开发,目前由Google赞助的OCR工具)。
我们的示例不是最实际的示例,而是要展示Tesseract在检测不同类型的字体方面的强大功能:我们将验证Google徽标是否确实拼写出“ Google”:
public class GooglePage extends BasePage<GooglePage> {
@Autowired private OCR ocr;
...
public String getLogoText() {
return ocr.getText($("LOGO"));
}
}
public class GoogleSteps extends BaseSteps {
private GooglePage google;
...
@Then("the Google logo shows the correct text")
public void checkLogo() {
assertThat(google.getLogoText()).isEqualTo("Google");
}
}
使用的OCR服务如下所示:
public class OCR implements qa.justtestlah.stubs.OCR {
private Logger LOG = LoggerFactory.getLogger(OCR.class);
private TakesScreenshot driver;
private Tesseract ocr;
@Autowired
public OCR(Tesseract ocr) {
this.ocr = ocr;
}
/**
* @param element {@link WebElement} element to perform OCR on
* @return recognised text of the element
*/
public String getText(WebElement element) {
return getText(element.getScreenshotAs(OutputType.FILE));
}
/** @return all text recognised on the screen */
public String getText() {
return getText(getScreenshot());
}
private String getText(File file) {
LOG.info("Peforming OCR on file {}", file);
try {
return ocr.doOCR(file).trim();
} catch (TesseractException exception) {
LOG.warn("Error performing OCR", exception);
return null;
}
}
/**
* Usage:
*
* <pre>
* new OCR().withDriver(driver);
* </pre>
*
* @param driver {@link WebDriver} to use for capturing screenshots
* @return this
*/
public OCR withDriver(WebDriver driver) {
this.driver = (TakesScreenshot) driver;
return this;
}
/**
* Usage:
*
* <pre>
* new OCR().withDriver(driver);
* </pre>
*
* @param driver {@link TakesScreenshot} to use for capturing screenshots
* @return this
*/
public OCR withDriver(TakesScreenshot driver) {
this.driver = driver;
return this;
}
private File getScreenshot() {
return driver.getScreenshotAs(OutputType.FILE);
}
@Override
public void setDriver(WebDriver driver) {
this.driver = (TakesScreenshot) driver;
}
}
这要求在运行测试的实例上安装Tesseract。有关完整的源代码和演示,请查看JustTestLah!测试框架。
- http://www.justtestlah.qa/
- 上一篇:opencv模板匹配识别logo
- 下一篇:常见的图像处理技术
相关推荐
- 悠悠万事,吃饭为大(悠悠万事吃饭为大,什么意思)
-
新媒体编辑:杜岷赵蕾初审:程秀娟审核:汤小俊审签:周星...
- 高铁扒门事件升级版!婚宴上‘冲喜’老人团:我们抢的是社会资源
-
凌晨两点改方案时,突然收到婚庆团队发来的视频——胶东某酒店宴会厅,三个穿大红棉袄的中年妇女跟敢死队似的往前冲,眼瞅着就要扑到新娘的高额钻石项链上。要不是门口小伙及时阻拦,这婚礼造型团队熬了三个月的方案...
- 微服务架构实战:商家管理后台与sso设计,SSO客户端设计
-
SSO客户端设计下面通过模块merchant-security对SSO客户端安全认证部分的实现进行封装,以便各个接入SSO的客户端应用进行引用。安全认证的项目管理配置SSO客户端安全认证的项目管理使...
- 还在为 Spring Boot 配置类加载机制困惑?一文为你彻底解惑
-
在当今微服务架构盛行、项目复杂度不断攀升的开发环境下,SpringBoot作为Java后端开发的主流框架,无疑是我们手中的得力武器。然而,当我们在享受其自动配置带来的便捷时,是否曾被配置类加载...
- Seata源码—6.Seata AT模式的数据源代理二
-
大纲1.Seata的Resource资源接口源码2.Seata数据源连接池代理的实现源码3.Client向Server发起注册RM的源码4.Client向Server注册RM时的交互源码5.数据源连接...
- 30分钟了解K8S(30分钟了解微积分)
-
微服务演进方向o面向分布式设计(Distribution):容器、微服务、API驱动的开发;o面向配置设计(Configuration):一个镜像,多个环境配置;o面向韧性设计(Resista...
- SpringBoot条件化配置(@Conditional)全面解析与实战指南
-
一、条件化配置基础概念1.1什么是条件化配置条件化配置是Spring框架提供的一种基于特定条件来决定是否注册Bean或加载配置的机制。在SpringBoot中,这一机制通过@Conditional...
- 一招解决所有依赖冲突(克服依赖)
-
背景介绍最近遇到了这样一个问题,我们有一个jar包common-tool,作为基础工具包,被各个项目在引用。突然某一天发现日志很多报错。一看是NoSuchMethodError,意思是Dis...
- 你读过Mybatis的源码?说说它用到了几种设计模式
-
学习设计模式时,很多人都有类似的困扰——明明概念背得滚瓜烂熟,一到写代码就完全想不起来怎么用。就像学了一堆游泳技巧,却从没下过水实践,很难真正掌握。其实理解一个知识点,就像看立体模型,单角度观察总...
- golang对接阿里云私有Bucket上传图片、授权访问图片
-
1、为什么要设置私有bucket公共读写:互联网上任何用户都可以对该Bucket内的文件进行访问,并且向该Bucket写入数据。这有可能造成您数据的外泄以及费用激增,若被人恶意写入违法信息还可...
- spring中的资源的加载(spring加载原理)
-
最近在网上看到有人问@ContextConfiguration("classpath:/bean.xml")中除了classpath这种还有其他的写法么,看他的意思是想从本地文件...
- Android资源使用(android资源文件)
-
Android资源管理机制在Android的开发中,需要使用到各式各样的资源,这些资源往往是一些静态资源,比如位图,颜色,布局定义,用户界面使用到的字符串,动画等。这些资源统统放在项目的res/独立子...
- 如何深度理解mybatis?(如何深度理解康乐服务质量管理的5个维度)
-
深度自定义mybatis回顾mybatis的操作的核心步骤编写核心类SqlSessionFacotryBuild进行解析配置文件深度分析解析SqlSessionFacotryBuild干的核心工作编写...
- @Autowired与@Resource原理知识点详解
-
springIOCAOP的不多做赘述了,说下IOC:SpringIOC解决的是对象管理和对象依赖的问题,IOC容器可以理解为一个对象工厂,我们都把该对象交给工厂,工厂管理这些对象的创建以及依赖关系...
- java的redis连接工具篇(java redis client)
-
在Java里,有不少用于连接Redis的工具,下面为你介绍一些主流的工具及其特点:JedisJedis是Redis官方推荐的Java连接工具,它提供了全面的Redis命令支持,且...
- 一周热门
- 最近发表
- 标签列表
-
- mybatiscollection (79)
- mqtt服务器 (88)
- keyerror (78)
- c#map (65)
- resize函数 (64)
- xftp6 (83)
- bt搜索 (75)
- c#var (76)
- mybatis大于等于 (64)
- xcode-select (66)
- mysql授权 (74)
- 下载测试 (70)
- linuxlink (65)
- pythonwget (67)
- androidinclude (65)
- logstashinput (65)
- hadoop端口 (65)
- vue阻止冒泡 (67)
- oracle时间戳转换日期 (64)
- jquery跨域 (68)
- php写入文件 (73)
- kafkatools (66)
- mysql导出数据库 (66)
- jquery鼠标移入移出 (71)
- 取小数点后两位的函数 (73)