自动化测试简介
每天在多个浏览器和设备上手动运行测试多次,可能会变得繁琐且耗时。为了高效地处理这个问题,您应该熟悉自动化工具。在本文中,我们将探讨可用的工具,如何使用任务运行器,以及如何使用商业浏览器测试自动化应用程序(如 Sauce Labs、BrowserStack 和 TestingBot)的基础知识。
预备知识 | 熟悉核心 HTML、CSS 和 JavaScript 语言;对跨浏览器测试的高级原则有所了解。 |
---|---|
目标 | 旨在提供对自动化测试的理解,了解它如何让您的工作更轻松,以及如何利用一些能简化工作的商业产品。 |
自动化让事情变得简单
在本模块中,我们详细介绍了测试您的网站和应用程序的多种不同方法,并解释了您的跨浏览器测试工作在要测试的浏览器、可访问性考虑等方面应具备的范围。听起来工作量很大,不是吗?
我们同意——手动测试我们在前几篇文章中讨论过的所有内容确实很痛苦。幸运的是,有一些工具可以帮助我们自动化这些痛苦。在本模块中,我们可以通过两种主要方式自动化我们一直在讨论的测试:
- 使用任务运行器,例如 Grunt 或 Gulp,或者 npm 脚本,在构建过程中运行测试和清理代码。这是一种很好的方式来执行诸如代码 Linting 和压缩、添加 CSS 前缀或转译新兴 JavaScript 功能以实现最大的跨浏览器覆盖等任务。
- 使用像 Selenium 这样的浏览器自动化系统,在已安装的浏览器上运行特定测试并返回结果,在浏览器出现故障时提醒您。像 Sauce Labs 和 BrowserStack 这样的商业跨浏览器测试应用程序都基于 Selenium,但允许您使用界面远程访问它们的设置,省去了您自己设置测试系统的麻烦。
我们将在下一篇文章中介绍如何设置自己的基于 Selenium 的测试系统。在本文中,我们将介绍如何设置任务运行器,并使用上述商业系统的基本功能。
注意:以上两类并非互斥。可以设置任务运行器,通过 API 访问 Sauce Labs 或 LambdaTest 等服务,运行跨浏览器测试并返回结果。我们将在下面也讨论这一点。
使用任务运行器自动化测试工具
如上所述,您可以使用任务运行器在构建过程中的特定时刻自动运行所有需要运行的任务,从而大大加快常见的任务,例如代码 Linting 和压缩。例如,这可以是每次保存文件时,或在其他某个时刻。在本节中,我们将介绍如何使用 Node 和 Gulp(一种对初学者友好的选项)自动化任务运行。
设置 Node 和 npm
如今,大多数工具都基于 Node.js,因此您需要安装它及其配套的包管理器 npm
。
- 安装和更新 Node.js 和
npm
最简单的方法是通过 Node 版本管理器:请按照 安装 Node 中的说明进行操作。 - 在继续之前,请务必测试您的安装是否成功。
- 如果您之前安装过 Node.js/
npm
,则应将其更新到最新版本。这可以通过使用节点版本管理器安装最新的 LTS 版本来完成(再次参考上面链接的说明)。
要开始在项目中使用基于 Node/npm 的包,您需要将项目目录设置为 npm 项目。这很容易做到。
例如,让我们首先创建一个测试目录,以便我们可以在不担心破坏任何东西的情况下进行操作。
-
使用文件管理器 UI 在某个合适的位置创建新目录,或者在命令行上,导航到所需位置并运行以下命令
bashmkdir node-test
-
要使此目录成为 npm 项目,您只需进入您的测试目录并使用以下命令对其进行初始化:
bashcd node-test npm init
-
第二个命令会问您很多问题,以获取设置项目所需的信息;您现在可以只选择默认值。
-
所有问题回答完毕后,它会询问您输入的信息是否正确。输入
yes
并按 Enter/Return,npm 将在您的目录中生成一个package.json
文件。
此文件基本上是项目的配置文件。您可以稍后自定义它,但现在它看起来像这样
{
"name": "node-test",
"version": "1.0.0",
"description": "Test for npm projects",
"main": "index.js",
"scripts": {
"test": "test"
},
"author": "Chris Mills",
"license": "MIT"
}
有了这个,您就可以继续了。
设置 Gulp 自动化
让我们来看看如何设置 Gulp 并使用它来自动化一些测试工具。
-
首先,使用上一节底部详述的程序创建一个测试 npm 项目。另外,使用行:
"type": "module"
更新package.json
文件,使其看起来像这样json{ "name": "node-test", "version": "1.0.0", "description": "Test for npm projects", "main": "index.js", "scripts": { "test": "test" }, "author": "Chris Mills", "license": "MIT", "type": "module" }
-
接下来,您需要一些示例 HTML、CSS 和 JavaScript 内容来测试您的系统 — 在您的项目文件夹中名为
src
的子文件夹中复制我们的示例 index.html、main.js 和 style.css 文件。如果您愿意,可以尝试自己的测试内容,但请记住,此类工具不适用于 HTML 文件中内联的 JS/CSS — 您需要单独的文件。 -
使用以下命令全局安装 gulp(这意味着它将适用于所有项目)
bashnpm install --global gulp-cli
-
接下来,在您的 npm 项目目录根目录中运行以下命令,将 gulp 设置为项目的依赖项
bashnpm install --save-dev gulp
-
现在在您的项目目录中创建一个名为
gulpfile.mjs
的新文件。这个文件将运行我们所有的任务。在这个文件中,放入以下内容jsimport gulp from "gulp"; export default function (cb) { console.log("Gulp running"); cb(); }
这需要我们之前安装的
gulp
模块,然后导出一个默认任务,除了向终端打印一条消息外,什么也不做——这对于让我们知道 Gulp 正在工作很有用。在接下来的几节中,我们将把这个export default
语句更改为更有用的内容。每个 Gulp 任务都以相同的基本格式导出 —
exports function taskName(cb) {...}
。每个函数都带有一个参数 — 一个在任务完成时运行的回调。 -
您可以使用以下命令运行 gulp 的默认任务 — 现在试试看
bashgulp
向 Gulp 添加一些实际任务
现在我们准备向 Gulp 文件添加更多任务。每次添加可能都需要您按以下方式修改 gulpfile.mjs
文件
- 当我们要求您添加一些
import
语句时,请将它们添加到现有import
语句下方。 - 当我们要求您添加新的
export function ...
语句时,请将其添加到文件的末尾。 - 当我们要求您更改默认导出时,请按照我们指定的方式更改
export default
语句。
所以你的 gulpfile.mjs
文件会这样增长
import gulp from "gulp";
// Add any new imports here
// Our latest default export
// export default ...
// Add any new task exports here
// export function ...
// export function ...
为了向 Gulp 添加一些实际任务,我们需要考虑我们想要做什么。以下是项目要运行的一组合理的基本功能:
- html-tidy, css-lint 和 js-hint 用于 Linting 并报告/修复常见的 HTML/CSS/JS 错误(参见 gulp-htmltidy, gulp-csslint, gulp-jshint)。
- Autoprefixer 用于扫描我们的 CSS 并仅在需要时添加供应商前缀(参见 gulp-autoprefixer)。
- babel 用于将任何新的 JavaScript 语法功能转译为可在旧浏览器中运行的传统语法(参见 gulp-babel)。
有关我们正在使用的不同 gulp 包的完整说明,请参阅上面的链接。
要使用每个插件,您需要先通过 npm 安装它,然后在 gulpfile.mjs
文件顶部导入所有依赖项,然后将您的测试添加到文件底部,最后导出任务名称以通过 gulp 的命令使用。
html-tidy
-
使用以下命令安装
bashnpm install --save-dev gulp-htmltidy
注意:
--save-dev
将包作为依赖项添加到您的项目中。如果您查看项目的package.json
文件,您将在devDependencies
属性中看到它的条目。 -
将以下依赖项添加到
gulpfile.mjs
jsimport htmltidy from "gulp-htmltidy";
-
将以下测试添加到
gulpfile.mjs
的底部jsexport function html() { return gulp .src("src/index.html") .pipe(htmltidy()) .pipe(gulp.dest("build")); }
-
将默认导出更改为
jsexport default html;
这里我们使用 gulp.src()
获取我们的开发 index.html
文件,这允许我们获取源文件来做一些事情。
接下来,我们使用 pipe()
函数将该源传递给另一个命令以进行其他操作。我们可以根据需要将任意多个这些操作链接在一起。我们首先对源文件运行 htmltidy()
,它会遍历并修复文件中的错误。第二个 pipe()
函数将输出的 HTML 文件写入 build
目录。
在文件的输入版本中,您可能已经注意到我们放了一个空的 <p>
元素;htmltidy 在输出文件创建时已经将其删除。
自动前缀和 CSS Lint
-
使用以下行安装
bashnpm install --save-dev gulp-autoprefixer npm install --save-dev gulp-csslint
-
将以下依赖项添加到
gulpfile.mjs
jsimport autoprefixer from "gulp-autoprefixer"; import csslint from "gulp-csslint";
-
将以下测试添加到
gulpfile.mjs
的底部jsexport function css() { return gulp .src("src/style.css") .pipe(csslint()) .pipe(csslint.formatter("compact")) .pipe( autoprefixer({ cascade: false, }), ) .pipe(gulp.dest("build")); }
-
将以下属性添加到
package.json
json{ "browserslist": ["last 5 versions"] }
-
将默认任务更改为
jsexport default gulp.series(html, css);
在这里,我们抓取 style.css
文件,对其运行 csslint(它将 CSS 中的任何错误列表输出到终端),然后通过 autoprefixer 运行它,以添加任何必要的前缀,使新兴的 CSS 功能在旧浏览器中运行。在管道链的末尾,我们将修改后的前缀 CSS 输出到 build
目录。请注意,这仅在 csslint 没有发现任何错误时才有效——尝试从 CSS 文件中删除一个花括号并重新运行 gulp,看看您会得到什么输出!
js-hint 和 babel
-
使用以下行安装
bashnpm install --save-dev gulp-babel @babel/preset-env npm install --save-dev @babel/core npm install jshint gulp-jshint --save-dev
-
将以下依赖项添加到
gulpfile.mjs
jsimport babel from "gulp-babel"; import jshint from "gulp-jshint";
-
将以下测试添加到
gulpfile.mjs
的底部jsexport function js() { return gulp .src("src/main.js") .pipe(jshint()) .pipe(jshint.reporter("default")) .pipe( babel({ presets: ["@babel/env"], }), ) .pipe(gulp.dest("build")); }
-
将默认任务更改为
jsexport default gulp.series(html, css, js);
在这里,我们抓取 main.js
文件,对其运行 jshint
,并使用 jshint.reporter
将结果输出到终端;然后我们将文件传递给 babel,它将其转换为旧式语法,并将结果输出到 build
目录。我们的原始代码包含一个 胖箭头函数,babel 已将其修改为旧式函数。
更多想法
设置好这一切之后,您可以在项目目录中运行 gulp
命令,您应该会得到如下输出
然后,您可以通过查看 build
目录中的文件,并在网络浏览器中加载 build/index.html
来试用自动化任务输出的文件。
如果出现错误,请检查您是否已按上述方式添加了所有依赖项和测试;还可以尝试注释掉 HTML/CSS/JavaScript 代码段,然后重新运行 gulp,看看是否可以找出问题所在。
Gulp 附带一个 watch()
函数,您可以使用它来监视文件并在每次保存文件时运行测试。例如,尝试将以下内容添加到 gulpfile.mjs
的底部
export function watch() {
gulp.watch("src/*.html", html);
gulp.watch("src/*.css", css);
gulp.watch("src/*.js", js);
}
现在尝试在终端中输入 gulp watch
命令。Gulp 将现在监视您的目录,并在您保存对 HTML、CSS 或 JavaScript 文件所做的更改时运行相应的任务。
注意: *
字符是通配符——这里我们说的是“当这些类型中的任何文件被保存时运行这些任务”。您也可以在主要任务中使用通配符,例如 gulp.src('src/*.css')
将获取所有 CSS 文件,然后对它们运行管道任务。
Gulp 还有很多功能。 Gulp 插件目录 中有数千个插件可供搜索。
其他任务运行器
还有许多其他任务运行器可用。我们当然不是说 Gulp 是最好的解决方案,但它对我们来说很有效,而且对于初学者来说也很容易上手。您也可以尝试使用其他解决方案:
- Grunt 的工作方式与 Gulp 非常相似,不同之处在于它依赖于配置文件中指定的任务,而不是使用编写的 JavaScript。有关更多详细信息,请参阅 Grunt 入门。
- 您还可以直接使用
package.json
文件中的 npm 脚本运行任务,而无需安装任何额外的任务运行器系统。这是基于 Gulp 插件之类的东西基本上是命令行工具的包装器的前提。因此,如果您能弄清楚如何使用命令行运行这些工具,那么您就可以使用 npm 脚本运行它们。它使用起来有点棘手,但对于那些擅长命令行技能的人来说可能会有回报。为什么选择 npm 脚本? 提供了一个很好的介绍和大量进一步的信息。
使用商业测试服务加速浏览器测试
现在让我们来看看商业第三方浏览器测试服务以及它们能为我们做什么。
当您使用这类服务时,您需要提供要测试页面的 URL 以及其他信息,例如您希望在哪些浏览器中进行测试。然后,应用程序会配置一个带有您指定操作系统和浏览器的新虚拟机,并以屏幕截图、视频、日志文件、文本等形式返回测试结果。这非常有用,并且比您自己设置所有操作系统/浏览器组合方便得多。
然后,您可以更进一步,使用 API 以编程方式访问功能,这意味着这些应用程序可以与任务运行器(例如您自己的本地 Selenium 环境和其他)结合使用,以创建自动化测试。
注意:还有其他可用的商业浏览器测试系统,但在本文中,我们将重点关注 BrowserStack、Sauce Labs 和 TestingBot。我们并不是说这些一定是最好的工具,但它们是很好的工具,初学者可以轻松上手。
浏览器堆栈
BrowserStack 入门
开始
- 创建 BrowserStack 试用账户。
- 登录。验证您的电子邮件地址后,这应该会自动发生。
- 单击顶部导航菜单中的实时链接,进入实时手动测试。
基础知识:手动测试
BrowserStack Live 仪表板允许您选择要测试的平台、设备和浏览器。对于桌面测试,您可以直接选择操作系统和浏览器。对于移动设备,您选择移动操作系统、设备,然后可以为您的设备-浏览器组合选择一个浏览器。
点击其中一个浏览器图标将加载您选择的平台、设备和浏览器——现在选择一个并试一试。
您可以在地址栏中输入 URL,通过鼠标拖动上下滚动,并在支持的设备(如 MacBooks)的触摸板上使用适当的手势(例如,捏合/缩放,双指滚动)。
可用功能因加载的浏览器而异,可能包括以下控件:
- 显示当前浏览器信息
- 切换到其他浏览器
- 测试本地主机 URL
- 设置缩放级别并切换方向
- 保存和加载书签
- 捕获/注释屏幕截图并提交错误报告
- 访问浏览器开发工具
- 更改报告位置
- 限制网络
- 访问屏幕阅读器
有关更多信息,请参阅 BrowserStack Live 文档。
高级:BrowserStack API
BrowserStack 还提供 RESTful API,允许您以编程方式检索账户计划、会话、构建等详细信息。
让我们简要了解一下如何使用 Node.js 访问 API。
-
首先,按照设置 Node 和 npm 中详述的步骤,设置一个新的 npm 项目来测试它。使用与之前不同的目录名称,例如
bstack-test
。 -
在项目根目录中创建一个新文件
call_bstack.js
,并为其指定以下内容:jsconst axios = require("axios"); const bsUser = "BROWSERSTACK_USERNAME"; const bsKey = "BROWSERSTACK_ACCESS_KEY"; const baseUrl = `https://${bsUser}:${bsKey}@www.browserstack.com/automate/`; function getPlanDetails() { axios.get(`${baseUrl}plan.json`).then((response) => { console.log(response.data); }); /* Response: { automate_plan: <string>, terminal_access: <string>. parallel_sessions_running: <int>, team_parallel_sessions_max_allowed: <int>, parallel_sessions_max_allowed: <int>, queued_sessions: <int>, queued_sessions_max_allowed: <int> } */ } getPlanDetails();
-
将 BrowserStack 用户名和访问密钥的占位符替换为您的实际值。这些可以从您的 BrowserStack 账户和个人资料详细信息的“身份验证和安全”部分检索。
-
通过在终端中运行以下命令,安装我们用于处理发送 HTTP 请求的 axios 模块(我们选择 axios 是因为它简单、流行且受良好支持):
bashnpm install axios
-
确保您的 JavaScript 文件已保存,并通过在终端中执行以下命令来运行它。您应该会看到一个对象打印到终端,其中包含您的 BrowserStack 计划详细信息。
bashnode call_bstack
下面我们还提供了一些其他现成的函数,您在处理 BrowserStack RESTful API 时可能会觉得有用。
此函数返回所有以前创建的自动化构建的摘要详细信息(有关 BrowserStack 自动化测试详细信息,请参见下一篇文章)
function getBuilds() {
axios.get(`${baseUrl}builds.json`).then((response) => {
console.log(response.data);
});
/* Response:
[
{
automation_build: {
name: <string>,
hashed_id: <string>,
duration: <int>,
status: <string>,
build_tag: <string>,
public_url: <string>
}
},
{
automation_build: {
name: <string>,
hashed_id: <string>,
duration: <int>,
status: <string>,
build_tag: <string>,
public_url: <string>
}
},
// …
]
*/
}
此函数返回特定构建的特定会话的详细信息
function getSessionsInBuild(build) {
const buildId = build.automation_build.hashed_id;
axios.get(`${baseUrl}builds/${buildId}/sessions.json`).then((response) => {
console.log(response.data);
});
/* Response:
[
{
automation_session: {
name: <string>,
duration: <int>,
os: <string>,
os_version: <string>,
browser_version: <string>,
browser: <string>,
device: <string>,
status: <string>,
hashed_id: <string>,
reason: <string>,
build_name: <string>,
project_name: <string>,
logs: <string>,
browser_url: <string>,
public_url: <string>,
appium_logs_url: <string>,
video_url: <string>,
browser_console_logs_url: <string>,
har_logs_url: <string>,
selenium_logs_url: <string>
}
},
{
automation_session: {
// …
}
},
// …
]
*/
}
以下函数返回一个特定会话的详细信息
function getSessionDetails(session) {
const sessionId = session.automation_session.hashed_id;
axios.get(`${baseUrl}sessions/${sessionId}.json`).then((response) => {
console.log(response.data);
});
/* Response:
{
automation_session: {
name: <string>,
duration: <int>,
os: <string>,
os_version: <string>,
browser_version: <string>,
browser: <string>,
device: <string>,
status: <string>,
hashed_id: <string>,
reason: <string>,
build_name: <string>,
project_name: <string>,
logs: <string>,
browser_url: <string>,
public_url: <string>,
appium_logs_url: <string>,
video_url: <string>,
browser_console_logs_url: <string>,
har_logs_url: <string>,
selenium_logs_url: <string>
}
}
*/
}
高级:自动化测试
我们将在下一篇文章中介绍运行自动化的 BrowserStack 测试。
酱实验室
Sauce Labs 入门
让我们从 Sauce Labs 试用开始吧。
- 创建 Sauce Labs 试用帐户。
- 登录。验证您的电子邮件地址后,这应该会自动发生。
基础知识:手动测试
Sauce Labs 仪表板上有许多可用的选项。登录后,请遵循页面左上角的“开始入门”指南
- 在“运行您的第一个测试”中,单击桌面浏览器。
- 在下一个屏幕中,输入您要测试的页面 URL(例如此页面),然后使用不同的按钮和列表选择要测试的浏览器/操作系统组合。您会发现有很多可供选择!
- 当您开始测试时,将出现一个加载屏幕,并启动一个运行您选择的设备/浏览器组合的环境。然后您可以开始远程测试在所选浏览器中运行的网站。
此时您可以做很多事情,例如共享测试 URL,以便其他人可以远程观察测试,将文本/注释复制到远程剪贴板,截屏,在全屏模式下测试等等。
一旦您停止会话,您将返回到实时选项卡,在那里您会看到您启动的每个先前手动会话的条目。点击其中一个条目会显示更多会话数据。在这里,您可以下载您拍摄的任何屏幕截图,观看会话视频,查看数据日志等等。这已经非常有用,比您自己设置多个模拟器和虚拟机方便得多。
有关更多信息,请参阅 Sauce Labs 文档。
高级:Sauce Labs API
Sauce Labs 有一个 RESTful API,允许您以编程方式检索您的账户和现有测试的详细信息,并用更多细节注释测试,例如它们的通过/失败状态,这无法仅通过手动测试记录。例如,您可能希望使用 Sauce Labs 远程运行您自己的 Selenium 测试,以测试特定的浏览器/操作系统组合,然后将测试结果传回 Sauce Labs。
它有几个可用的客户端,允许您使用您喜欢的环境(无论是 PHP、Java、Node.js 等)调用 API。
让我们简要了解一下如何使用 Node.js 和 node-saucelabs 访问 API。
-
首先,按照设置 Node 和 npm 中详述的步骤,设置一个新的 npm 项目来测试它。使用与之前不同的目录名称,例如
sauce-test
。 -
使用以下命令安装 Node Sauce Labs 封装器:
bashnpm install saucelabs
-
在您的项目根目录中创建一个名为
call_sauce.js
的新文件。给它以下内容:jsconst SauceLabs = require("saucelabs").default; (async () => { const myAccount = new SauceLabs({ username: "your-sauce-username", password: "your-sauce-api-key", }); // Get full WebDriver URL from the client depending on region: console.log(myAccount.webdriverEndpoint); // Get job details of last run job const jobs = await myAccount.listJobs("your-sauce-username", { limit: 1, full: true, }); console.log(jobs); })();
-
您需要将您的 Sauce Labs 用户名和 API 密钥填入指定位置。这些可以从您的 用户设置 页面获取。现在填写这些信息。
-
确保所有内容都已保存,然后按如下方式运行文件
bashnode call_sauce
高级:自动化测试
我们将在下一篇文章中介绍实际运行自动化的 Sauce Lab 测试。
测试机器人
TestingBot 入门
让我们从 TestingBot 试用开始。
- 创建一个 TestingBot 试用账户。
- 登录。验证您的电子邮件地址后,这应该会自动发生。
基础知识:手动测试
TestingBot 仪表板 列出了您可以选择的各种选项。目前,请确保您在实时网页测试选项卡上。
- 输入您要测试的页面 URL。
- 通过在网格中选择组合来选择您要测试的浏览器/操作系统组合。
- 当您点击启动浏览器时,将出现一个加载屏幕,启动一个运行您所选组合的虚拟机。
- 加载完成后,您就可以开始远程测试在所选浏览器中运行的网站了。
- 从这里您可以看到它在您正在测试的浏览器中可能呈现的布局,移动鼠标并尝试点击按钮等。侧面菜单允许您:
- 停止会话
- 更改屏幕分辨率
- 将文本/注释复制到远程剪贴板
- 截取、编辑和下载屏幕截图
- 在全屏模式下测试。
一旦您停止会话,您将返回到实时网页测试页面,在那里您会看到您启动的每个先前手动会话的条目。点击其中一个条目会显示更多会话数据。在这里,您可以下载您拍摄的任何屏幕截图,观看测试视频,并查看会话日志。
高级:TestingBot API
TestingBot 有一个 RESTful API,允许您以编程方式检索您的账户和现有测试的详细信息,并用更多细节注释测试,例如它们的通过/失败状态,这无法仅通过手动测试记录。
TestingBot 有多个 API 客户端可供您用来与 API 交互,包括用于 NodeJS、Python、Ruby、Java 和 PHP 的客户端。
下面是一个示例,展示如何使用 NodeJS 客户端 testingbot-api 与 TestingBot API 交互。
-
首先,按照设置 Node 和 npm 中详述的步骤,设置一个新的 npm 项目来测试它。使用与之前不同的目录名称,例如
tb-test
。 -
使用以下命令安装 Node TestingBot 封装器
bashnpm install testingbot-api
-
在您的项目根目录中创建一个名为
tb.js
的新文件。为其指定以下内容:jsconst TestingBot = require("testingbot-api"); let tb = new TestingBot({ api_key: "your-tb-key", api_secret: "your-tb-secret", }); tb.getTests((err, tests) => { console.log(tests); });
-
您需要将您的 TestingBot 密钥和秘密填入指定位置。您可以在 TestingBot 仪表板中找到它们。
-
确保所有内容都已保存,然后运行文件
bashnode tb.js
高级:自动化测试
我们将在下一篇文章中介绍实际运行自动化的 TestingBot 测试。
总结
这真是一段旅程,但我相信您已经开始看到使用自动化工具来完成测试中的繁重工作所带来的好处。
在下一篇文章中,我们将介绍如何使用 Selenium 设置我们自己的本地自动化系统,以及如何将其与 Sauce Labs、BrowserStack 和 TestingBot 等服务结合使用。