运行测试#

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

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

本地测试#

几乎所有的Bokeh测试都可以在本地运行。然而,有些测试在本地系统上设置和正确运行可能会比较复杂。因此,当你在Bokeh的GitHub仓库上创建一个Pull Request时,所有测试都将在Bokeh的CI中运行。你不需要在本地设置和运行所有测试

遵循以下一般准则来决定在本地运行哪些测试:

Whenever you change anything in Bokeh’s codebase

运行Bokeh的代码库测试

When you edit Bokeh’s Python code

运行Bokeh的Python单元测试

When your work involves UI elements

运行Bokeh的Python集成测试

When your change anything related to BokehJS

运行Bokeh的JavaScript测试

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

检查基本要求#

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

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

一些测试还需要在您的系统上安装Selenium和相应的web driver。虽然可以使用其他web驱动程序进行某些测试,但推荐的设置是使用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来说,在处理基于Bokeh的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 文档 获取更多选项。

Unit tests

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

pytest -m "not selenium" tests/unit

注意

此命令将排除需要Selenium的单元测试。因为 Selenium可能难以设置,而且一些单元测试需要 geckodriverChromeDriver在您的系统上可用, 使用-m "not selenium"是本地运行单元测试的推荐方式。一旦您创建拉取请求Bokeh的CI将运行所有测试,包括 基于Selenium的单元测试。如果您的系统上同时有Selenium、geckodriver和 ChromeDriver可用,您可以使用pytest tests/unit运行所有单元测试。

Code coverage (Python unit tests)

要为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的文档

Cross integration tests

有一些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的指南来创建健壮的集成测试。

Run all available tests

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

pytest
Select specific tests

要测试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。您需要在系统上安装这些浏览器的最新版本,以便在本地运行这些测试。

运行所有BokehJS测试#

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

pytest tests/test_bokehjs.py

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

node make test

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

选择特定的BokehJS测试#

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

  • 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 测试框架会自动启动浏览器,并使用正确的设置以产生一致的测试结果。

使用开发工具服务器进行测试#

除了从命令行运行BokehJS测试外,您还可以使用BokehJS开发工具服务器。此系统要求您的系统上安装有Chrome网络浏览器。使用BokehJS开发工具服务器来运行测试并查看视觉测试的输出。

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

$ node test/devtools server
listening on 127.0.0.1:5777

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

Inspecting visual test results

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

Screenshot of devtool displaying a locally rendered image, an image diff and a baseline image.
Initiate test runs

你也可以使用开发工具服务器来启动测试运行。你有两种选择:

  • Run tests from a JavaScript console

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

    • /unit

    • /defaults

    • /integration

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

    Tests.run_all(query=/[Ll]egend/);
    
  • Use endpoint to run tests

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

    • /unit/run

    • /defaults/run

    • /integration/run

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

要仅运行或查看特定测试,请在URL后附加?k=some%20text。这将通过关键字过滤测试。

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

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

注意

在大多数情况下,使用常规的Chrome图形用户界面在本地运行测试的结果与在Bokeh的CI中使用无头版本的Chrome运行测试的结果是相同的。然而,在极少数情况下,无头Chrome和图形用户界面Chrome会产生不同的结果。在这种情况下,你不能使用图形用户界面——相反,你需要直接在无头浏览器中调试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)#

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

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

环境文件#

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

礼仪#

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