Python 测试框架:pytest(pytest.mark)
先用一个简单的例子,展示如何使用 pytest 来测试 Python 代码。
首先,确保你已经安装了 pytest。如果没有安装,可以通过 pip 安装:
pip install pytest
示例代码
假设我们有一个简单的 Python 模块 math_functions.py,它包含了一个函数 add_numbers,该函数接收两个数字作为参数并返回它们的和。
# math_functions.py
def add_numbers(a, b):
return a + b
编写测试
接下来,我们编写一个测试文件来测试 math_functions.py 中的 add_numbers 函数。测试文件通常以 test_ 开头,以便 pytest 能够自动识别并执行它们。
# test_math_functions.py
from math_functions import add_numbers
def test_add_numbers():
assert add_numbers(1, 2) == 3
assert add_numbers(-1, 1) == 0
assert add_numbers(0, 0) == 0
运行测试
现在,你可以通过命令行运行 pytest 来执行测试。只需在包含测试文件的目录中打开命令行或终端,并输入以下命令:
pytest
会自动找到所有以 test_ 开头的文件,并执行其中的测试函数。对于每个测试函数,pytest 都会创建一个新的测试环境(也称为测试用例),并执行该函数。如果断言(assert 语句)失败,pytest 会报告失败并显示相关的堆栈跟踪。
测试结果
如果 math_functions.py 中的 add_numbers 函数按预期工作,你将看到类似以下的测试结果:
============================= test session starts ==============================
platform darwin -- Python 3.x.x, pytest-x.x.x, py-1.x.x, pluggy-x.x.x
rootdir: /path/to/your/project
collected 1 item
test_math_functions.py . [100%]
============================== 1 passed in 0.02s ===============================
这里的 . 表示测试通过,而 1 passed 表示总共有 1 个测试通过。
这就是使用 pytest 编写和执行 Python 测试的基本流程。pytest 提供了许多高级功能,包括参数化测试、测试固件(setup/teardown)、跳过和标记测试等,这些功能可以帮助你编写更强大、更灵活的测试。
测复杂点
pytest.mark提供了多种标记(marks)来增强测试用例的灵活性和可管理性。我们将通过几个示例来展示如何使用pytest.mark.parametrize(参数化测试)、pytest.mark.skipif(条件跳过测试)和pytest.mark.xfail(预期失败测试)。
示例测试文件:test_marks.py
import pytest
# 使用 pytest.mark.parametrize 进行参数化测试
@pytest.mark.parametrize("test_input,expected", [
(1, 2),
(2, 3),
(3, 4),
])
def test_increment(test_input, expected):
assert test_input + 1 == expected
# 使用 pytest.mark.skipif 条件跳过测试
import sys
@pytest.mark.skipif(sys.version_info < (3, 7), reason="requires Python 3.7 or higher")
def test_python_version_dependent_feature():
# 假设这是一个依赖于Python 3.7+特性的测试
assert True
# 使用 pytest.mark.xfail 标记预期失败的测试
@pytest.mark.xfail(reason="known issue, will be fixed in the next release")
def test_known_failure():
# 假设这个测试因为某个已知问题而失败
assert False
# 还可以将多个标记组合使用
@pytest.mark.parametrize("num", [1, 2, 3])
@pytest.mark.skipif(sys.version_info < (3, 8), reason="skip on Python < 3.8")
def test_multiple_marks(num):
# 假设这个测试既需要参数化,又需要在Python 3.8+上运行
assert num + 1 > 1, "this should always pass, but might be skipped"
# 标记一个测试类
@pytest.mark.slow
class TestSlowFeatures:
def test_feature_a(self):
# 假设这是一个运行较慢的测试
assert True
def test_feature_b(self):
# 另一个运行较慢的测试
assert True
# 注意:上面的@pytest.mark.slow本身不会改变测试的执行方式,
# 它只是给测试或测试类添加了一个标记,你可以通过pytest的命令行选项来过滤或选择这些标记的测试。
运行测试
要运行这些测试,你只需在命令行中执行pytest命令,并确保你的工作目录包含test_marks.py文件。
pytest
过滤标记的测试
pytest提供了命令行选项来过滤或选择带有特定标记的测试。例如,要只运行标记为slow的测试,你可以使用-m选项:
pytest -m slow
这将会运行所有标记为slow的测试,包括TestSlowFeatures类中的测试。
预期失败和跳过
test_known_failure由于被标记为xfail,即使它失败了,pytest也会将其视为通过(即“预期失败”)。test_python_version_dependent_feature会根据你的Python版本决定是否跳过。
通过这种方式,pytest.mark为测试提供了更多的灵活性和控制力。
另一个测试框 架参见:Python 测试框架:unittest (unittest.mock)
更多推荐
所有评论(0)