Mochitest

免责声明

如果您正在测试 Web 平台代码,建议使用 wpt 测试(最好是可上游的)。

简介

Mochitest 是一个基于 MochiKit JavaScript 库构建的自动化测试框架。

只有可以使用 JavaScript(具有 chrome 权限!)才能测试的内容才能使用此框架进行测试。如果有一定的创造力,实际上可以测试的内容比您最初想象的要多得多,但例如,无法编写 Mochitest 测试来直接测试非脚本化的 C++ 组件。(使用像 GTest 这样的编译代码测试来执行此操作。)

运行测试

要运行单个测试(可能是您刚刚添加的新测试)或整个 Mochitest 套件的子集,请将路径参数传递给 mach 命令。

例如,要仅运行 Mozilla 源代码树中 test_CrossSiteXHR.html 测试,您将运行以下命令

./mach test dom/security/test/cors/test_CrossSiteXHR.html

要运行 dom/svg/ 中的所有测试,此命令将起作用

./mach test dom/svg/

您还可以传递清单路径以运行该清单上的所有测试

./mach test dom/base/test/mochitest.ini

运行版本和子套件

版本是用于运行 Mochitest 的默认配置的变体。例如,某个版本可能具有一组略微不同的首选项设置,安装了自定义扩展,甚至在完全不同的范围内运行。

Mochitest 版本包括:

  • plain - 最基本和最常见的 Mochitest。它们在内容范围内运行,但可以使用 SpecialPowers 访问某些特权 API。

  • browser - 这些通常测试浏览器 UI 本身,并在浏览器窗口范围内运行。

  • chrome - 这些在 chrome 范围内运行,通常用于测试特权 JavaScript API。更多信息可以在 此处 找到。

  • a11y - 这些测试辅助功能接口。它们可以在顶级 accessible 目录下找到,并在 chrome 范围内运行。请注意,这些在没有 e10s / fission 的情况下运行。

子套件类似于版本,只是它具有相同的配置。它只是出于显示目的在逻辑上与“默认”子套件分离。例如,devtools 是 browser 版本的子套件。这两个作业的运行方式没有区别。它的存在是为了让 devtools 团队能够轻松查看和运行他们的测试。

注意:还有标签,类似于子套件。尽管两者都用于逻辑上对相关测试集进行分组,但它们的行为不同。例如,将子套件应用于测试会将该测试从默认集中移除,而标签不会将其移除。

默认情况下,mach 会找到并运行给定子目录中的每个测试,无论它属于哪个版本或子套件。但有时,您可能只想运行特定的版本或子套件。这可以通过分别使用 --flavor(或 -f)和 --subsuite 选项来实现。例如

./mach mochitest -f plain                        # runs all plain tests
./mach mochitest -f browser --subsuite devtools  # runs all browser tests in the devtools subsuite
./mach mochitest -f chrome dom/indexedDB         # runs all chrome tests in the dom/indexedDB subdirectory

在许多情况下,无需按版本或子套件进行筛选,因为运行特定目录会隐式地执行此操作。例如,运行

./mach mochitest devtools/

大致等同于运行 devtools 子套件。在某些情况下,您可能希望运行不属于任何子套件的测试。为此,请使用

./mach mochitest --subsuite default

调试单个测试

如果您需要调试单个测试,您可以重新加载包含该测试的页面并附加调试器。如果在问题出现之前附加调试器很困难(例如,如果浏览器在加载测试时崩溃),则可以在运行 mochitest 时指定调试器

./mach mochitest --debugger=gdb ...

另请参阅 --debugger-args--debugger-interactive 参数。您还可以使用 --jsdebugger 参数调试 JavaScript。

查找错误

搜索字符串 TEST-UNEXPECTED-FAIL 以查找意外故障。您还可以搜索 SimpleTest FINISHED 以查看最终的测试摘要。

记录结果

测试运行的输出可以发送到控制台和/或文件(默认情况下,结果仅显示在浏览器中)。有几个详细级别可供选择。级别为 DEBUGINFOWARNINGERRORCRITICAL,其中 DEBUG 生成最高的详细程度(所有内容),而 CRITICAL 生成最低的详细程度。

Mochitest 使用结构化日志记录。这意味着您可以使用一组命令行参数来配置日志输出。要使用 mach 格式化程序记录到标准输出,并以 JSON 格式记录到文件,您可以使用 --log-mach=- --log-raw=mochitest.log。默认情况下,所有格式化程序的文件日志记录级别为 INFO,但您可以使用 --log-mach-level=<level> 更改它。

要打开控制台的日志记录,请使用 --console-level=<level>

例如,要使用默认 (tbpl) 格式化程序将测试运行输出记录到 ~/mochitest.log 文件,详细程度为 DEBUG 级别,您将使用

./mach mochitest --log-tbpl=~/mochitest.log --log-tbpl-level=DEBUG

无头模式

测试必须在聚焦窗口中运行,这有效地阻止了参与计算机上的任何其他用户活动。您可以通过使用 --headless 参数或 MOZ_HEADLESS=1 环境变量来避免这种情况。

./mach mochitest --headless ...

编写测试

Mochitest 普通测试只是一个 HTML 或 XHTML 文件,其中包含一些 JavaScript 用于测试某些条件。

异步测试

有时测试涉及异步模式,例如等待事件或观察者。在这些情况下,您需要使用 add_task

add_task(async function my_test() {
  let keypress = new Promise(...);
  // .. simulate keypress
  await keypress;
  // .. run test
});

当异步测试任务旨在为运行准备测试时,使用 add_setup()。所有设置任务都按其出现的顺序执行一次,在任何测试任务之前。

add_setup(async () => {
  await clearStorage();
});

或者,手动调用 waitForExplicitFinishfinish

SimpleTest.waitForExplicitFinish();
addEventListener("keypress", function() {
  // ... run test ...
  SimpleTest.finish();
}, false);
// ... simulate key press ...

如果您需要更多时间,requestLongerTimeout(number) 可能非常有用。requestLongerTimeout() 获取一个整数因子,它是默认 45 秒超时时间的乘数。因此,因子 2 表示:“等待至少 90 秒 (2*45 秒)”。如果您想暂停执行进行一些调试,这非常有用。

测试函数

每个测试都必须包含一些 JavaScript,这些 JavaScript 将运行并告诉 Mochitest 测试是否通过或失败。SimpleTest.js 为测试提供了一些函数,用于将结果传回给 Mochitest。这些包括

  • ok(expressionThatShouldBeTrue, "Description of the check") – 测试某个值是否为真

  • is(actualValue, expectedValue, "Description of the check") – 比较两个值(使用 Object.is)

  • isnot(actualValue, unexpectedValue, "Description of the check") – is() 的反面

如果您想包含对当前失败内容的测试,请不要仅仅将其注释掉!相反,请使用其中一个“todo”等价物,以便我们注意到它是否突然开始通过(此时可以重新启用测试)

  • todo(falseButShouldBeTrue, "Description of the check")

  • todo_is(actualValue, expectedValue, "Description of the check")

  • todo_isnot(actualValue, unexpectedValue, "Description of the check")

测试可以调用函数 info("Message string") 将消息写入测试日志。

除了 mochitest 断言之外,mochitest 还支持 CommonJS 标准断言,例如 nodejs 的 assert 模块,但在 Assert.sys.mjs 中实现。这些在浏览器版本中自动导入,但在其他版本中需要手动导入。

辅助函数

目前,派生自 MochiKit 的有用辅助函数在 testing/mochitest/tests/SimpleTest/SimpleTest.js 中可用。

尽管所有 Mochikit 都可以在 testing/mochitest/MochiKit 中使用,但仅包含您需要的文件以最大程度地减少测试加载时间。错误 367569 添加了 sendCharsendKeysendString 辅助函数。这些在 testing/mochitest/tests/SimpleTest/EventUtils.js 中可用。

如果您需要从 Mochitest 访问一些数据文件,您可以使用 SimpleTest.getTestFileURL("relative/path/to/data.file") 获取它们的 URI。然后,您可以最终使用 XMLHttpRequest 等方法获取其内容。

将测试添加到树中

mach addtest 是将测试添加到树中的首选方法。

./mach addtest --suite mochitest-{plain,chrome,browser-chrome} path/to/new/test

这将向相关的清单文件(mochitest.inichrome.ini 等,具体取决于版本)添加清单条目,以告知构建系统您的新测试,并根据模板创建文件。

[test_new_feature.html]

可以选择为您的测试指定元数据,例如是否在某些平台上跳过测试。

[test_new_feature.html]
skip-if = os == 'win'

解析器识别的 mochitest.ini 格式 定义了长长的元数据列表。

添加新的 mochitest.ini 或 chrome.ini 文件

如果在您想要添加测试的测试目录中不存在 mochitest.inichrome.ini 文件,请添加它们并更新测试目录中的 moz.build 文件。例如,在 gfx/layers/moz.build 中,我们添加了这两个清单文件。

MOCHITEST_MANIFESTS += ['apz/test/mochitest.ini']
MOCHITEST_CHROME_MANIFESTS += ['apz/test/chrome.ini']

常见问题

请参阅 Mochitest 常见问题解答页面,了解您可能想要使用的其他功能,例如支持 SSL 的测试、自定义 HTTP 标头、异步测试、泄漏调试、首选项等。