跳转至

编写、运行和测试代码

修复一个错误或实现一个功能,都需要你编写一些新代码。

开始编写代码前,请确保已搭建好开发环境,并处于开发分支上工作

我们有一份代码风格指南,其中概述了为 BeeWare 编写代码的规范。

测试驱动开发

确保代码能按预期运行的一个好方法是,先编写一个测试用例来验证它。这个测试用例起初应该会失败,因为它所测试的代码尚未存在。然后,你可以编写必要的代码修改以使测试通过,从而确信你所编写的代码确实解决了预期中的问题。

运行您的代码

编写完代码后,你需要确保它能够运行。你需要手动运行代码,以验证其运行结果是否符合预期。如果你尚未这样做,建议为所做的修改编写一个测试用例;如上所述,如果代码被注释掉或不存在,该测试应失败。

您将把测试用例添加到测试套件中,以便与其他测试一起运行。下一步是运行该测试套件。

运行测试 及覆盖率

BeeWare 使用 tox 来管理测试流程,并使用 pytest 作为其自身的测试套件。

默认的 tox 命令包括执行:

  • 提交前钩子
  • towncrier 版本说明检查
  • 文档代码检查

  • 适用于现有 Python 版本的测试套件

  • 代码覆盖率报告

这基本上就是你在提交拉取请求时,CI 所执行的操作。

要运行完整的测试套件,请执行:

(.venv) $ tox
(.venv) $ tox
(.venv) C:\...>tox

运行完整的测试套件可能需要一段时间。您可以通过并行运行 tox 来显著加快速度,具体方法是运行 tox p(或 tox run-parallel)。当您并行运行测试套件时,虽然在运行过程中收到的进度反馈会减少,但在测试结束时仍会获得发现问题的汇总报告。您应该会看到一些表明测试已运行的输出信息。 您可能会看到 SKIPPED 条测试,但绝不应该看到任何 FAILERROR 的测试结果。我们在合并每个补丁之前都会运行完整的测试套件。如果该过程发现任何问题,我们就不会合并该补丁。如果您确实发现了测试错误或失败,要么是您的测试环境存在异常,要么是您发现了一个我们之前未曾遇到的边界情况——无论哪种情况,请务必告知我们!

除了测试通过外,这还应显示 100% 测试覆盖率

运行测试变体

针对多个 Python 版本运行测试

默认情况下,许多 tox 命令会尝试多次运行测试套件,每次对应 BeeWare 支持的一个 Python 版本。不过,要实现这一点,您的机器上必须已安装每个 Python 版本,并且 tox 的 Python 检测 过程能够识别到它们。通常来说,如果某个 Python 版本可以通过 PATH 识别,那么 tox 应该能够找到并使用它。

仅运行测试套件

如果你正在对新功能进行快速迭代,则无需运行完整的测试套件;你可以运行单元测试。要实现这一点,请运行:

(.venv) $ tox -e py
(.venv) $ tox -e py
(.venv) C:\...>tox -e py

运行部分测试

默认情况下,tox 会运行单元测试套件中的所有测试。在开发新测试时,可能需要“仅”运行该测试。为此,您可以将 任何 pytest 指定符 作为参数传递给 tox。这些测试路径相对于 briefcase 目录。例如,若要仅运行单个文件中的测试,请执行:

(.venv) $ tox -e py -- tests/path_to_test_file/test_some_test.py
(.venv) $ tox -e py -- tests/path_to_test_file/test_some_test.py
(.venv) C:\...>tox -e py -- tests/path_to_test_file/test_some_test.py

即使只运行测试套件的一部分,您仍然会收到覆盖率报告——但覆盖率结果只会报告您所运行的特定测试所执行的代码行。

运行特定 Python 版本的测试套件

默认情况下,tox -e py 将使用您机器上解析为 python 的任意解释器运行。如果您安装了多个 Python 版本,并且希望从已安装的版本中测试某个特定版本,可以指定要使用的具体 Python 版本。例如,要在 Python 3.10 上运行测试套件,请执行以下命令:

(.venv) $ tox -e py310
(.venv) $ tox -e py310
(.venv) C:\...>tox -e py310

通过在命令行中添加 -- 和测试规范,可以运行 测试子集

不带覆盖率的测试套件(快速)

默认情况下,tox 会以单线程模式运行 pytest 测试套件。您可以通过并行运行测试套件来加快其执行速度。由于在子进程中捕获覆盖率较为复杂,此模式不会生成覆盖率文件。若要在“快速”模式下运行单个 Python 版本,请执行以下命令:

(.venv) $ tox -e py-fast
(.venv) $ tox -e py-fast
(.venv) C:\...>tox -e py-fast

可以通过在命令行中添加 -- 和测试规范来运行 测试子集;可以通过在测试目标中添加版本号来使用 特定的 Python 版本(例如,py310-fast 可在 Python 3.10 上快速运行)。

代码覆盖率

BeeWare 的代码库保持 100% 的分支覆盖率。当您在项目中添加或修改代码时,必须添加测试代码,以确保对所做的任何更改进行覆盖。

然而,BeeWare 支持多个平台以及多个 Python 版本,因此无法在单一平台和 Python 版本上验证完整的代码覆盖率。 为解决这一问题,在 tool.coverage.coverage_conditional_plugin.rulespyproject.toml 部分定义了若干条件覆盖规则(例如,no-cover-if-is-windows 可用于标记在 Windows 上运行测试套件时不会被执行的代码块)。这些规则用于识别仅在特定平台或 Python 版本上被覆盖的代码段。

需要注意的是,不同 Python 版本之间的覆盖率报告可能会有些特殊情况。例如,如果覆盖率文件是在某个 Python 版本下生成的,但报告是在另一个版本下生成的,那么报告中可能会出现因分支遗漏而导致的误报。因此,生成覆盖率报告时,应始终使用生成覆盖率文件时所用的最旧的 Python 版本。

理解覆盖结果

在覆盖率测试输出的末尾,应包含一份关于所收集覆盖率数据的报告:

名称    报表   缺失分支   分支部分   覆盖率   缺失
 ---------------------------------------------------
 合计    7540 0   1040 0  100.0%

这表明测试套件已经执行了代码中所有可能的分支路径。虽然这不能100%保证没有缺陷,但确实意味着我们已经对代码库中的每一行代码都进行了测试。

如果您对代码库进行了修改,可能会导致代码覆盖率出现缺口。一旦发生这种情况,覆盖率报告会告诉您哪些代码行未被执行。例如,假设我们对 some/interesting_file.py 进行了修改,添加了一些新逻辑。覆盖率报告可能如下所示:

名称 语句   缺失 分支 BrPart  覆盖率   缺失
 -------------------------------------------------------------------------------
 src/some/interesting_file.py 111 1     26 0  98.1%   170, 302-307, 320->335
 -------------------------------------------------------------------------------
 总计 7540 1     1726 0  99.9%

这表明第 170 行、第 302-307 行以及从第 320 行跳转到第 335 行的分支,均未被测试套件执行。您需要添加新的测试(或修改现有测试)来恢复该代码覆盖率。

主机平台和 Python 版本的覆盖率报告

您可以针对您所使用的 Python 平台和版本生成覆盖率报告。例如,若要在 Python 3.10 上运行测试套件并生成覆盖率报告,请执行以下命令:

(.venv) $ tox -m test310
(.venv) $ tox -m test310
(.venv) C:\...>tox -m test310

主机平台覆盖报告

如果 tox 可用所有受支持的 Python 版本,则可通过运行以下命令报告主机平台的代码覆盖率:

(.venv) $ tox p -m test-platform
(.venv) $ tox p -m test-platform
(.venv) C:\...>tox p -m test-platform

HTML 中的覆盖率报告

通过在任何覆盖率 -html 环境名称后添加 tox,即可生成 HTML 覆盖率报告,例如:

(.venv) $ tox -e coverage-platform-html
(.venv) $ tox -e coverage-platform-html
(.venv) C:\...>tox -e coverage-platform-html

这不仅仅是写测试!

尽管我们确保对所有代码都进行了测试,但这项工作不仅仅是维持这种测试水平。其中一部分工作是在开发过程中对代码进行审查。你可以为一件混凝土救生衣编写一套全面的测试用例……但这件混凝土救生衣对于其原本的用途来说,依然毫无用处!

在编写测试时,你还应检查核心模块在内部是否也具有一致性。 如果您发现任何方法名称在内部不一致(例如,某个方法在某个模块中名为 on_select,但在另一个模块中却名为 on_selected),或者数据处理方式不一致,请标记该问题并通过提交工单告知我们。或者,如果您确信自己知道该如何处理,请创建一个拉取请求来修复您发现的问题。

当您完成所有操作后,即可提交包含您修改内容的拉取请求