运行测试#

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

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

本地测试#

Bokeh 的几乎所有测试都可以在本地运行。但是,一些测试在本地系统上设置和运行起来可能很复杂。因此,当您 创建拉取请求 到 Bokeh 的 GitHub 存储库时,所有测试将在 Bokeh 的 CI 中运行。您无需在本地设置和运行所有测试

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

只要您更改了 Bokeh 代码库中的任何内容

运行 Bokeh 的 代码库测试

当您编辑 Bokeh 的 Python 代码时

运行 Bokeh 的 Python 单元测试

当您的工作涉及 UI 元素时

运行 Bokeh 的 Python 集成测试

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

运行 Bokeh 的 JavaScript 测试

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

检查基本要求#

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

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

一些测试还需要 Selenium 和相应的 网络驱动程序 可用在您的系统上。虽然可以使用其他网络驱动程序进行某些测试,但建议的设置是使用 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 集成测试

以下是一些在使用 Bokeh 的 pytest 基测试时需要了解的 pytest 命令行参数

  • -k:提供一个搜索字符串来过滤特定测试。请参阅 选择特定测试

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

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

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

  • --driver:对基于 Selenium 的测试使用特定的网络驱动程序 ("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" 是在本地运行单元测试的推荐方法。一旦您 创建拉取请求Bokeh 的 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 测试#

大多数针对 BokehJS 的基于 JavaScript 的测试使用自定义的测试框架。此框架 **需要 Google Chrome 或 Chromium**。您需要在您的系统上提供最新版本的这些浏览器之一才能在本地运行这些测试。

运行所有 BokehJS 测试#

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

pytest tests/test_bokehjs.py

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

node make test

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

选择特定的 BokehJS 测试#

您还可以选择单独运行这些测试套件,在源代码签出的 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 网页浏览器在您的系统上可用。使用 BokehJS devtools 服务器来运行测试并查看视觉测试的输出。

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

$ node test/devtools server
listening on 127.0.0.1:5777

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

检查视觉测试结果

运行集成测试后,您可以使用 devtools 服务器将您的本地结果与基线图像进行比较。在 Chrome 网页浏览器中打开显示的服务器 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 控制台运行测试

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

    • /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 的无头版本。但是,在某些情况下,无头和 GUI Chrome 会生成不同的结果。在这种情况下,您无法使用 GUI - 而是需要直接在无头浏览器中调试 BokehJS 的代码。有关更多信息,请参阅 在无头 Chrome 中调试

运行示例测试#

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

示例测试使用主题测试框架,包括 Chrome 的自定义配置。因此,**建议不要在本地运行这些测试**。相反,Bokeh 的 CI 在您 创建拉取请求 后会运行所有示例测试。

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

cd bokehjs
node make test:run:headless

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

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)#

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

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

环境文件#

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

礼仪#

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