机器学习驱动的Web测试自动化

APPLICATION Jan 3, 2025

我的测试自动化之旅始于 1995 年左右,当时 Web 应用程序几乎不存在,桌面软件是常态。UI 自动化虽然简单,但经常不稳定,为什么?对象识别和同步操作,这些一直是稳健重复 UI 自动化的挑战。

快进到今天,Web 应用程序无处不在,但 Web UI 测试自动化仍然是一个挑战,原因并没有改变。使用 Angular 和 React 等框架的 Web 应用程序具有复杂的生命周期流程。Web 工程师面临着同步数据和 UI 的艰巨任务。那么测试工程师还有什么希望呢?

Playwright 和 Cypress 等工具试图尽可能多地解决这些痛点。更改底层 HTML 以创建钩子和方便的交互方式已成为标准做法。那么接下来是什么?机器学习,也许。在本文中,我将描述一些 ML 分支,我曾用它们来实际尝试解决问题。

我的挑战;如何登录到任何地方的任何网站,而无需使用底层 HTML 与对象交互。

需要注意的是,这个假设与抓取或机器人使用无关,之所以选择这个想法是因为网站数量庞大,用户身份验证方式各异。

1、问题陈述

网站上的典型用户身份验证将从登录或登录按钮开始。实际上,用户在继续之前也经常需要接受 cookie。除了一些异常值外,其余过程都很好理解!

现在让我们将每个过程分解为机器学习的分支,并解释为什么使用这些分支。

接受、注册、登录、登录通常被视为按钮,因此我们只有一个必需的操做 Click()。输入字段需要 Click()Type Events。这些是大多数 Web 应用程序所需的唯一人机交互。

在这个简单的用户身份验证示例中,我使用了以下 ML 分支。

  • 对象检测
  • 分类
  • 分割
  • 自然语言处理/文本处理
用户身份验证流程图
为什么这么多 ML 子领域?

当我们使用典型的 Web 应用程序时,人类大脑正在寻找关键指标。我们已经习惯于寻找某些关键字,这些词通常是按钮或链接上的名称,或者是我们应该用鼠标指向并单击的东西。表单字段通常被一个框包围,因此我们预先确定要通过示例进行定位。

因此,当我们转换这些任务中的每一个时,我们也可以将它们分解为用户交互。因此,对象检测和分类是主要分支,但我们还需要处理文本并定位或包围某些对象。

2、对象检测(按钮/链接)

该模型是使用 Yolov9 构建的,数据集没有增强。类的总数为 9,但是像 Register这样的类的表示很少。

我用于构建对象检测部分的数据集使用了以下主要类。数据集包含 440 张网站图像,以 1024 x 640 的快照拍摄并标记。

登录是最常见的情况,但登录也可以是“登录”或“登录”—事实上有很多不同的字体和变体。

因此,对象检测非常擅长广泛地挑选每个类别。直到模型与类似的对象混淆。例如“登录”和“退出”。

随着准确度的提高,模型指标显示出良好的稳定曲线。epoch 数为 25,尽管需要大量的 GPU 处理。我可能可以将其降低到更低的值。在 30 次模型运行中,我确实看到了过度拟合,但数据标注并不好玩,准确度足以完成这项练习。

对象检测训练指标

不过,Roboflow 中有一个非常好的功能,可以使用你自己的模型作为标记预测器。不过,我还是要小心,尽量贴近我所要限制的对象,因为这会对模型的准确性产生很大的影响。

为了解决检测到类似对象的问题,我使用了单一分类,它用于重新验证最初预测的类别。这意味着要建立一个工作流程,Roboflow 在这方面做得非常好。

该模型对诸如登录和接受等类别的精度非常高。这完全可能是由于表示和位置。“接受”按钮经常出现在图像的下半部分,而“登录”按钮则出现在右上角。

使用动态裁剪来提取预测的类别。最初,预测设置得相当高,大约 60%,但我发现 Yolov9 模型在低预测分数下没有出现垃圾邮件。因此,对象检测设置为 10%,最大检测设置为 5。

对象检测和分类工作流程

3、单一分类(按钮/链接)

模型是使用 Yolo8n 构建的,数据集包含 2500 张图像。我使用了一些简单的脚本来生成图像及其变体的多个版本。我假设大多数网站都有传统的字体样式。例如,登录比登录更频繁,所以我用同样的方法分割文本。

我还对这个分类使用了增强,这生成了一个大约 6K 幅图像的数据集

工作流程结果的总体结果非常有希望。结合预测意味着我可以可靠地重新确认或构建一些简单的逻辑来最大化正确的结果。如果登录和注册或登录,在对象检测阶段被错误预测。分类几乎正确地预测了这些值。

只有在发现字体或样式的重大偏差时,才会发现对象检测完全失败。Comic Sans 或非常不寻常的字体可能属于 10% 的对象检测过滤器。

最初考虑使用输出数据来输入第三个模型。虽然我希望没有代码,并且可以考虑使用某种形式的元建模。我意识到,对于我的示例,逻辑很容易解决这个问题。我还担心连续模型堆叠本身会带来其他因素。

所以我的零代码,实际上意味着零 HTML/CSS 浏览器对象交互开始看起来相当整洁。

await pageManager.navigateTo("https://www.codecademy.com");
homePage = new HomePage(pageManager.getPage());

await homePage.accept.click();
await homePage.logIn.click();

上面的示例使用了 puppeteer,按钮元素的底层代码块如下:

export type UIElementButton = {
    click: () => Promise<void>;
    label: string;
    model: "form-segmentation" | "auth-detection";
}

这一切听起来都很棒,但仍有更多工作要做。我如何实际单击该对象。由于模型返回的 JSON 包含位置坐标,我们可以将其发送给 Puppeteer。我在触发事件之前标记了点击位置。

4、分割(表单字段)

该模型是一个 Yolov8s,有 45 幅图像,其中包含与用户名和密码相关的输入字段。表单字段不变地有两种方法。第一种是在上面嵌入文本或字段标签,或在其中嵌入占位符。有时标签在上面,带有额外的占位符。

使用简单的 15% 旋转应用增强来增加数据集的占用空间。这将数据集扩展到 107 张图像。

分割出人意料地非常准确,通常达到 80% 的可预测性。然而,分配输入框的角色是一个挑战。提供用户名的方法有很多种,如何识别正确的用户名需要一个基于文本的模型。

最初,我的工作流程会截取输入屏幕截图并识别分割框。然后,OCR 将识别分割内的任何文本。

分割和 OCR 提取工作流程

Roboflow 有一个很棒的功能,它允许你使用内置模型。在此工作流程中,在分割检测之后,Roboflow 插件模型 OCR 用于提取边界区域内的任何内容。

分割和 OCR JSON 输出

使用两个堆叠的模型,结果非常惊人,我们现在可以定位和提取输入字段及其相关文本。

不幸的是,Roboflow 无法为工作流程上传自定义模型。因此,我们现在有了输入的位置,以及与输入相关的文本,我们现在只需要对其进行分类,即用户名和密码。

5、文本分类(表单字段验证)

通过使用简单的 LogisticRegression 模型,我们知道文本分类可以产生很好的结果。

from sklearn.feature_extraction.text import CountVectorizer
from sklearn.linear_model import LogisticRegression
import joblib

X = [
    "email", "username", "user id", "please enter username", "email address", "user name",
    "password", "password123", "enter password", "please enter password", "user password"
]
y = ["username", "username", "username", "username", "username", "username",
     "password", "password", "password", "password", "password"]

vectorizer = CountVectorizer()
X_vect = vectorizer.fit_transform(X)

model = LogisticRegression()
model.fit(X_vect, y)

joblib.dump(model, "classification_model.pkl") 
joblib.dump(vectorizer, "vectorizer.pkl")

结果非常令人印象深刻,下面显示了例如,用户名的文本值为“Email*”,其值为 71%。因此,通过少量逻辑,我们可以再次参考原始分割模型输出,即我们需要提取位置坐标的预测。

Predictions received: [
      { label: 'password', probability: 69.06, text: 'Password*' },
      { label: 'username', probability: 71.55, text: 'Email*' }
]

最后是 Puppeteer 与输入元素进行交互的代码:

export type UIElementInput = {
    click: () => Promise<void>;
    fill: (keys: string) => Promise<void>;
    label: string;
    model: "form-segmentation" | "auth-detection";
}

await pageManager.navigateTo("https://www.codecademy.com");
homePage = new HomePage(pageManager.getPage());
// Accept/Login
await homePage.username.fill("usermame@example.com");
await homePage.password.fill("Password123!");
await homePage.login.click();

一旦识别出输入字段,Puppeteer 将单击输入元素并触发键盘敲击:

机器学习/输入交互后的图像

6、结束语

测试自动化市场规模巨大,随着底层网络技术的变化,工程师的切入点总是在变化。显然,Web UI 测试不仅在维护方面成本高昂,还可以使用更强大的技术(如组件模拟)来降低成本,这可以减少所需的 UI 测试数量,但不会完全消除。

前面提到的测试自动化的两个痛点,即对象识别和同步,并没有通过这种方法神奇地消失。我仍然发现自己在等待与对象交互,或者我应该在什么时候截取屏幕截图。事实上,这里有一个问题表,但这并不是全部。

与 ML/UI 自动化相关的问题

但是,这只是一种方法,我看不出有什么理由无法在未来构建自定义站点相关模型。提取表单字段非常准确,交互事件也非常简单,只需“单击”和“键入”即可。

我没有涉及的是从网页中提取信息。我之前曾使用过分类技术 ,例如playwright-classification库。同样,这需要对可以对哪些图像进行分类进行大量思考。

我还可以看到如何提取表格,这也是一个考虑因素,另一个库playwright-tables可用于构建数据框以提供测试期望。

还有可能获得 Transformer Architecture,例如 chatGPT 来支持 Web 交互模型。以下语句可能是以某种形式在数千次测试中发现的:

Given I am Bob Sanders with valid credentials
When I authenticate on the system
Then I should be able to see my account details

代码量也很少,可以在这里找到 https://github.com/serialbandicoot/puppeteer-metal

那么我的方法解决了问题吗,即使仍然有点不稳定?

我认为不久之后,我们就会看到像 Playwright 这样的初创公司和巨头加入这一行列。因为最终这将成为一个数据科学问题,解决视觉回归问题,因为 Web UI 自动化测试中重复、无聊但又非常重要的任务仍然至关重要。

我留给你一个完整演示的视频,请注意终端中来自模型的预测值和流量。这肯定是未来。


原文链接:Enhancing Web UI Test Automation with Machine Learning

汇智网翻译整理,转载请标明出处

Tags