Help us learn about your current experience with the documentation. Take the survey.
Python 风格指南
测试
概述
GitLab 的测试,包括 Python 代码库中的测试,是核心优先事项,而不是事后补充。因此,从一开始就应考虑测试设计质量与功能设计同等重要。
使用 Pytest 进行 Python 测试。
推荐阅读
测试层次
在编写测试之前,了解不同的测试层次,并确定适合您更改的测试层次。
了解更多关于不同测试层次的信息,以及如何决定您的更改应该在哪个层次进行测试。
建议
测试文件名应与被测试文件名相同
对于单元测试,使用 test_{被测试文件}.py 命名测试文件,并将其放在相同的目录结构中,有助于后续测试的发现。这也可以避免同名文件但不同模块之间的混淆。
File: /foo/bar/cool_feature.py
# Bad
Test file: /tests/my_cool_feature.py
# Good
Test file: /tests/foo/bar/test_cool_feature.py使用 NamedTuples 定义参数化测试用例
Pytest 参数化测试 有效减少了代码重复,但它们依赖元组来定义测试用例,不像 Ruby 那样有更易读的语法。随着参数或测试用例的增加,这些基于元组的测试变得越来越难以理解和维护。
通过使用 Python NamedTuples,您可以:
- 通过命名字段强制执行更清晰的组织。
- 使测试更具自文档性。
- 轻松定义参数的默认值。
- 在复杂的测试场景中提高可读性。
# Good: Short examples, with small numbers of arguments. Easy to map what each value maps to each argument
# 良好:简短的示例,参数数量少。容易映射每个值到每个参数
@pytest.mark.parametrize(
(
"argument1",
"argument2",
"expected_result",
),
[
# description of case 1,
# 用例 1 的描述,
("value1", "value2", 200),
# description of case 2,
# 用例 2 的描述,
...,
],
)
def test_get_product_price(argument1, argument2, expected_result):
assert get_product_price(value1, value2) == expected_cost
# Bad: difficult to map a value to an argument, and to add or remove arguments when updating test cases
# 不良:难以将值映射到参数,并且在更新测试用例时难以添加或删除参数
@pytest.mark.parametrize(
(
"argument1",
"argument2",
"argument3",
"expected_response",
),
[
# Test case 1:
# 测试用例 1:
(
"value1",
{
...
},
...
),
# Test case 2:
# 测试用例 2:
...
]
)
def test_my_function(argument1, argument2, argument3, expected_response):
...
# Good: NamedTuples improve readability for larger test scenarios.
# 良好:NamedTuples 提高了大型测试场景的可读性。
from typing import NamedTuple
class TestMyFunction:
class Case(NamedTuple):
argument1: str
argument2: int = 3
argument3: dict
expected_response: int
TEST_CASE_1 = Case(
argument1="my argument",
argument3={
"key": "value"
},
expected_response=2
)
TEST_CASE_2 = Case(
...
)
@pytest.mark.parametrize(
"test_case", [TEST_CASE_1, TEST_CASE_2]
)
def test_my_function(test_case):
assert my_function(case.argument1, case.argument2, case.argument3) == case.expected_response模拟
- 使用
unittest.mock库。 - 在适当的级别进行模拟,例如在方法调用边界处。
- 模拟外部服务和 API。
代码风格
建议使用自动化工具来确保代码质量和安全。 考虑在 CI 管道和本地运行以下工具:
格式化工具
- Black:强制执行一致风格的代码格式化工具
- isort:排序和组织导入语句
代码检查工具
- flake8:检查 PEP-8 合规性和常见错误
- pylint:更全面的代码质量检查工具
- mypy:Python 静态类型检查器
测试工具
- pytest:带有覆盖率报告的测试框架
安全工具
- 依赖扫描:检查依赖项中的漏洞
- 秘密检测:确保没有秘密被提交到仓库
- SAST (semgrep):静态应用程序安全测试