运行测试#

Bokeh 是一个大型、多语言的项目,依赖于复杂而全面的测试和测试工具,以帮助确保一致性并防止回归。

本章介绍如何在 本地开发环境Bokeh 在 GitHub 上的持续集成 (CI) 系统 中运行各种测试。

本地测试#

几乎所有 Bokeh 的测试都可以在本地运行。但是,某些测试在本地系统上设置和正确运行可能很复杂。因此,当您在 Bokeh 的 GitHub 仓库上 创建 Pull Request 时,所有测试都将在 Bokeh 的 CI 中运行。 您无需在本地设置和运行所有测试

遵循以下通用指南来决定在本地运行哪些测试

每当您更改 Bokeh 代码库中的任何内容时

运行 Bokeh 的 代码库测试

当您编辑 Bokeh 的 Python 代码时

运行 Bokeh 的 Python 单元测试

当您的工作涉及 UI 元素时

运行 Bokeh 的 Python 集成测试

当您更改与 BokehJS 相关的任何内容时

运行 Bokeh 的 JavaScript 测试

作为参考,本节概述了所有可用的测试以及如何在大多数系统上本地运行它们。一般来说,仅运行与您正在处理的内容相关的特定测试是最有意义的。有关如何选择和取消选择特定 Python 测试的说明,请参阅 选择特定测试。有关如何选择和取消选择特定 BokehJS 测试的说明,请参阅 选择特定 BokehJS 测试

检查基本要求#

在尝试在本地运行 Bokeh 测试之前,请确保您已成功完成本贡献者指南的 设置开发环境 章节中的所有步骤。

检查 Bokeh 的示例数据 是否已安装并为最新版本,方法是运行 pip install bokeh_sampledata。如果您无法在系统上安装示例数据,您可以选择 禁用这些特定测试

一些测试还需要 Selenium 和相应的 web driver 在您的系统上可用。虽然可以使用其他 web driver 进行某些测试,但推荐的设置是将 Selenium 与 ChromeDriverChrome 一起使用。有关安装说明和更多信息,请参阅 其他依赖项。如果 Selenium 在您的系统上不可用,您可以选择 禁用这些特定测试

在某些 Unix 平台上,您可能还需要增加“最大打开文件描述符数”。 某些测试在测试服务器时会打开许多文件,因此此数字应至少为 1024。

ulimit -n 1024

运行代码库测试#

最基本的测试集是 Bokeh 的代码库测试。 这包括使用 Ruff 检查 Python 代码,使用 ESLint 检查 JavaScript 代码,以及各种其他测试,例如未使用的导入和多余的空格。

您对 Bokeh 的 Python 或 JavaScript 代码库所做的任何编辑都应该通过此测试。

从仓库的顶层运行此命令

pytest tests/codebase

运行 Python 测试#

Bokeh 包含许多专注于 Bokeh 的 Python 代码的测试。这些测试使用 pytest,位于 tests 文件夹中。

每当您使用 Bokeh 的 Python 代码时,您都应该运行 Bokeh 的 代码库Python 单元测试。如果您的工作还包括对用户界面元素的更改,您还应该运行 Bokeh 的 Python 集成测试

以下是一些 pytest 的命令行参数,在处理基于 pytest 的 Bokeh 测试时很有用

  • -k:提供搜索字符串以筛选特定测试。请参阅 选择特定测试

  • -m:根据标记选择或取消选择特定测试。请参阅 选择特定测试

  • -n:在多个 CPU 或内核上分配测试。提供一个数字来定义要使用的内核数。设置为 auto 以使用所有可用内核。例如:pytest -n 4 tests/codebase。请参阅 pytest-xdist

  • -v:以更详细的输出运行测试。

  • --driver:为基于 Selenium 的测试使用特定的 web driver("chrome""firefox""safari")。例如:pytest --driver="firefox" tests/unit/

  • --no-js:跳过任何 JavaScript 代码,仅测试 Python 代码。

有关更多选项,请参阅 pytest 文档

单元测试

要运行 Bokeh 的 Python 单元测试,请在仓库的顶层使用以下命令

pytest -m "not selenium" tests/unit

注意

此命令将排除需要 Selenium 的单元测试。由于 Selenium 可能难以设置,并且某些单元测试需要 geckodriverChromeDriver 在您的系统上都可用,因此建议使用 -m "not selenium" 来在本地运行单元测试。一旦您 创建 Pull RequestBokeh 的 CI 将运行所有测试,包括基于 Selenium 的单元测试。如果 Selenium 以及 geckodriver 和 ChromeDriver 在您的系统上都可用,您可以使用 pytest tests/unit 运行所有单元测试。

代码覆盖率(Python 单元测试)

要为 Python 单元测试创建覆盖率报告,请将 pytest 与命令行选项 --cov=bokeh 一起使用

pytest --cov=bokeh

Bokeh 的 Python 单元测试的覆盖率应在 90% 左右。 覆盖率报告仅与 Python 单元测试相关。 其他 Python 测试或 BokehJS 的任何 JavaScript 代码都没有覆盖率报告。

您还可以选择在运行 Python 单元测试的特定子集时添加 --cov=bokeh。 这会将覆盖率报告添加到测试结果中。 例如

pytest --cov=bokeh --cov-report=html -m "not selenium" tests/unit/bokeh/test_objects.py

另请参阅

覆盖率报告使用 pytest 插件 pytest-cov。 有关更多信息,请参阅 pytest-cov 文档

交叉集成测试

有一些 Python 到 JS 接口测试,在 Bokeh 端,运行 Python 代码示例(测试用例),该示例生成带有序列化文档的 JSON 输出。 该 JSON 随后存储在仓库中的 tests/baselines/cross 下。 添加新的测试用例时,运行

pytest tests/test_cross.py

然后提交任何新的基线并重新运行测试。 只有提交的基线才会被测试运行器考虑。

每个测试用例都必须在 BokehJS 中有一个对应的集成测试,位于 bokehjs/test/integration/cross.ts 下。 这些等同于典型的 BokehJS 集成测试。 但是,建议对于不需要检查输出的视觉方面的测试,跳过图像差异。 请注意,跳过图像捕获不会禁用 *.blf 文件的生成。

请注意,交叉测试用例必须经过仔细设计,以便 BokehJS 可以运行它们,从而产生一致且可重复的输出,尤其是在捕获图像时。 与其他类型的测试一样,允许使用随机数据,因为测试运行器会为 Python 和 numpy 的随机数生成器设定种子。 遵循 BokehJS 的指南来创建健壮的集成测试。

运行所有可用测试

您可以通过从顶层目录运行以下命令来运行所有可用测试(Python 和 JavaScript 单元测试、示例和集成测试)

pytest
选择特定测试

要测试 Bokeh 包的子集,请将路径传递给 pytest

pytest tests/unit/bokeh/models/

同样,您可以通过将特定文件传递给 pytest 来运行特定测试

pytest tests/unit/bokeh/models/test_grids.py

选择或取消选择特定测试的另一种方法是使用标记。 目前,Bokeh 的测试使用以下两个标记

  • sampledata:需要下载 bokeh.sampledata 的测试

  • selenium:需要 selenium 的测试

有关设置您自己的标记的更多信息,请参阅 使用自定义标记,该文档位于 pytest 文档中。 要了解有关 pytest 用于选择特定测试的各种选项的更多信息,请参阅 指定要运行的测试

另请参阅

有关添加和更新 Python 测试的信息,请参阅 编写 Python 测试

运行 JavaScript 测试#

大多数基于 JavaScript 的 BokehJS 测试都使用自定义的测试框架。 此框架 需要 Google Chrome 或 Chromium。 您需要在系统上安装最新版本的这些浏览器之一,才能在本地运行这些测试。 Bokeh 将尝试在您的 PATH 中查找 Google Chrome 或 Chromium,但您可以设置环境变量 BOKEH_CHROME 以指向可执行文件(如果需要)。

运行所有 BokehJS 测试#

您可以使用 pytest 运行所有可用的 BokehJS 测试

pytest tests/test_bokehjs.py

这是运行所有 BokehJS 测试的快捷方式。 您可以使用 node make 直接从源 checkout 的 bokehjs 子目录中运行相同的测试集

node make test

这将运行代码库、默认值、单元和集成测试套件的组合。

选择特定 BokehJS 测试#

您还可以选择单独运行这些测试套件,方法是在源 checkout 的 bokehjs 子目录中使用 node make test:suite_name

  • node make test:codebase:代码库测试,检查文件大小限制

  • node make test:defaults:测试,检查 Bokeh 的 Python 模型中的默认值是否与 Bokeh 的 JavaScript 模型中的默认值匹配

  • node make test:unit:BokehJS 的单元测试

  • node make test:integration:视觉集成测试,将本地生成的绘图与一组基线文件进行比较

您可以通过运行 node make test:lib 来组合最后两个测试套件。

此外,您可以使用搜索字符串来选择单个测试或测试组。 使用 -k 参数来提供您的搜索字符串。 搜索字符串区分大小写。 BokehJS 测试框架尝试将您的搜索字符串与测试的 describe()it() 函数中定义的字符串匹配。 例如

$ node make test:integration -k "Legend"

这将仅运行包含字符串“Legend”的集成测试。

注意

BokehJS 单元测试和集成测试需要最新版本的 Chrome 或 Chromium。 BokehJS 测试框架会自动启动浏览器,并使用正确的设置来产生一致的测试结果。

使用 devtools 服务器进行测试#

除了从命令行运行 BokehJS 测试外,您还可以使用 BokehJS devtools 服务器。 此系统需要 Chrome web 浏览器在您的系统上可用。 使用 BokehJS devtools 服务器来运行测试并查看视觉测试的输出。

首先,使用以下命令从 bokehjs 子目录启动 devtools 服务器

$ node test/devtools server
listening on 127.0.0.1:5777

您现在可以使用 devtools 服务器进行以下操作

检查视觉测试结果

运行集成测试后,您可以使用 devtools 服务器将您的本地结果与基线图像进行比较。 在 Chrome web 浏览器中打开显示的服务器 URL(通常为 127.0.0.1:5777),并附加 /integration/report。 这将打开任何测试的比较视图,其中您本地渲染的绘图与基线文件不同。 例如

Screenshot of devtool displaying a locally rendered image, an image diff and a baseline image.
启动测试运行

您还可以使用 devtools 服务器来启动测试运行。 您有两个选项

  • 从 JavaScript 控制台运行测试

    在您的 web 浏览器中打开以下三个端点之一

    • /unit

    • /defaults

    • /integration

    这将加载 BokehJS 和测试。 要运行测试,请在 Chrome 的 JavaScript 控制台中发出 Tests.run_all()。 这允许您在运行代码之前设置断点。 您还可以传递搜索字符串、字符串列表或正则表达式作为函数的 query 参数,以仅运行特定测试。 例如

    Tests.run_all(query=/[Ll]egend/);
    
  • 使用端点来运行测试

    通过使用浏览器访问以下端点之一来启动测试运行

    • /unit/run

    • /defaults/run

    • /integration/run

    Screenshot of devtool displaying various plots as a result of running integration tests.

要仅运行或查看特定测试,请将 ?k=some%20text 附加到 URL。 这将按关键字筛选测试。

要仅运行或查看特定平台的测试,请将 platform=linuxplatform=macosplatform=windows 附加到 URL。

有关添加和更新 BokehJS 测试的信息,请参阅 编写 JavaScript 测试 (BokehJS)

注意

在大多数情况下,使用常规 Chrome GUI 在本地运行测试的结果与在 Bokeh 的 CI 中运行测试的结果相同,后者使用 Chrome 的无头版本。 但是,在极少数情况下,无头 Chrome 和 GUI Chrome 会生成不同的结果。 在这种情况下,您不能使用 GUI - 相反,您需要在无头浏览器中直接调试 BokehJS 的代码。 有关更多信息,请参阅 在无头 Chrome 中调试

运行示例测试#

除了 Bokeh 专注于 Python 和 JavaScript 的测试之外,Bokeh 还使用一套示例测试。 此套件运行 Bokeh 仓库中的示例选择,以检查每个示例是否在没有生成错误的情况下构建。 运行这些测试还会生成包含这些绘图屏幕截图的报告。

示例测试使用主题测试框架,包括 Chrome 的自定义配置。 因此,建议不要在本地运行这些测试。 相反,一旦您 创建 Pull RequestBokeh 的 CI 就会运行所有示例测试。

要在本地运行示例测试,您首先需要在后台启动 Chrome 的自定义无头版本。 此无头浏览器需要从 bokehjs 文件夹启动。 从您的 *源 checkout* 目录的顶层使用以下命令

cd bokehjs
node make test:run:headless

这将启动一个无头 Chrome 工具。 接下来,打开第二个终端,并从您的 *源 checkout* 目录的顶层运行测试

pytest tests/test_examples.py

运行测试时,pytest 还会生成一个报告,其中包含每个示例的视觉输出的屏幕截图。 这些屏幕截图在 examples-report.html 中可用。 此文件位于您从中运行测试的同一目录中

Screenshot of a browser window displaying an examples test report consisting of various plots.

注意

示例测试不分析生成的屏幕截图,因此不会根据视觉输出而失败。 您需要手动检查测试报告。

此外,示例测试会在同一目录中生成一个名为 examples.log 的日志文件。

持续集成 (CI)#

每次您在 Bokeh 的 GitHub 仓库上启动 Pull Request 或向现有 Pull Request 分支添加新提交时,Bokeh 的持续集成 (CI) 将在您的分支上运行所有可用测试。

您可以在此 URL 查看所有当前和以前的 CI 运行列表:bokeh/bokeh

环境文件#

Bokeh 的 CI 在 Linux、macOS 和 Windows 上运行测试。 它还使用不同版本的 Python 运行测试。 各种测试环境在 conda 文件夹中各自的 YAML 文件中定义。 如果您添加或更改依赖项,则需要更新这些文件。

礼仪#

CI 服务为开源项目提供有限的免费构建 worker。 请在推送到 GitHub 之前将您的提交分组为有意义的工作块,而不是单独推送每个提交。 这将帮助您体谅其他需要访问这些有限资源的人。