🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
# Pytest 教程 > 原文: [http://zetcode.com/python/pytest/](http://zetcode.com/python/pytest/) Pytest 教程展示了如何使用 Pytest 模块测试 Python 应用。 ## python Pytest Pytest 是用于测试 Python 应用的 Python 库。 它是鼻子测试和单元测试的替代方法。 ## Pytest 安装 使用以下命令安装 Pytest: ```py $ pip install pytest ``` 这将安装 Pytest 库。 ## Pytest 测试发现约定 如果未指定任何参数,则在`testpaths`(如果已配置)或当前目录中的位置搜索测试文件。 另外,命令行参数可以在目录,文件名或节点 ID 的任何组合中使用。 Pytest 在所选目录中查找`test_*.py`或`*_test.py`文件。 在选定的文件中,Pytest 在类之外查找带前缀的测试函数,并在带前缀的测试类中查找带前缀的测试方法(无`__init__()`方法)。 ## 运行 Pytest Pytest 不带任何参数,将查看当前工作目录(或其他一些预配置的目录)以及测试文件的所有子目录,并运行找到的测试代码。 ```py $ pytest ``` 运行当前目录中的所有测试文件。 ```py $ pytest min_max_test.py ``` 我们可以通过指定名称作为参数来运行特定的测试文件。 ```py $ pytest min_max_test.py::test_min ``` 可以通过在`::`字符后提供其名称来运行特定函数。 ```py $ pytest -m smoke ``` 标记可用于对测试进行分组。 然后使用`pytest -m`运行一组标记的测试。 ```py $ pytest -k <expression> ``` 另外,我们可以使用表达式来运行与测试函数和类的名称匹配的测试。 ## Python Pytest 简单示例 在第一个示例中,我们将使用 Pytest 测试两个简单的数学算法。 `algo.py` ```py def max(values): _max = values[0] for val in values: if val > _max: _max = val return _max def min(values): _min = values[0] for val in values: if val < _min: _min = val return _min ``` 我们有一个带有自定义`max()`和`min()`函数的模块。 `min_max_test.py` ```py #!/usr/bin/env python3 import algo def test_min(): values = (2, 3, 1, 4, 6) val = algo.min(values) assert val == 1 def test_max(): values = (2, 3, 1, 4, 6) val = algo.max(values) assert val == 6 ``` 测试文件`min_max_test.py`的名称中包含一个测试词。 ```py def test_min(): values = (2, 3, 1, 4, 6) val = algo.min(values) assert val == 1 ``` 此外,测试函数`test_min()`具有测试字。 我们使用`assert`关键字来测试算法的值。 ```py $ pytest min_max_test.py ================================================= test session starts ================================================= platform win32 -- Python 3.7.0, pytest-5.0.1, py-1.8.0, pluggy-0.12.0 rootdir: C:\Users\Jano\Documents\pyprogs\pytest collected 2 items min_max_test.py .. [100%] ============================================== 2 passed in 0.03 seconds =============================================== ``` 这是输出。 有两个测试,并且都成功通过了。 `pytest -v min_max_test.py`显示了更详细的输出。 ## Pytest 跳过 使用跳过装饰器,我们可以跳过指定的测试。 跳过测试有多种原因。 例如,数据库/在线服务目前不可用,或者我们跳过了 Windows 上针对 Linux 的特定测试。 `skipping.py` ```py #!/usr/bin/env python3 import algo import pytest @pytest.mark.skip def test_min(): values = (2, 3, 1, 4, 6) val = algo.min(values) assert val == 1 def test_max(): values = (2, 3, 1, 4, 6) val = algo.max(values) assert val == 6 ``` 在示例中,`test_min()`被跳过。 ```py $ pytest min_max_test.py ================================================= test session starts ================================================= platform win32 -- Python 3.7.0, pytest-5.0.1, py-1.8.0, pluggy-0.12.0 rootdir: C:\Users\Jano\Documents\pyprogs\pytest collected 2 items min_max_test.py s. [100%] ========================================= 1 passed, 1 skipped in 0.04 seconds ========================================= ``` 在测试文件名后面的输出中,`s`代表跳过的和。 通过。 ## Pytest 标记 我们可以使用标记将测试组织为单元。 `marking.py` ```py #!/usr/bin/env python3 # pytest -m a marking.py # pytest -m b marking.py import pytest @pytest.mark.a def test_a1(): assert (1) == (1) @pytest.mark.a def test_a2(): assert (1, 2) == (1, 2) @pytest.mark.a def test_a3(): assert (1, 2, 3) == (1, 2, 3) @pytest.mark.b def test_b1(): assert "falcon" == "fal" + "con" @pytest.mark.b def test_b2(): assert "falcon" == f"fal{'con'}" ``` 我们有两组由标记`a`和`b`标识的测试。 这些单元由`pytest -m a marking.py`和`pytest -m b marking.py`运行。 ## Pytest 参数化测试 通过参数化测试,我们可以向断言中添加多个值。 我们使用`@pytest.mark.parametrize`标记。 `parametrized.py` ```py #!/usr/bin/env python3 import algo import pytest @pytest.mark.parametrize("data, expected", [((2, 3, 1, 4, 6), 1), ((5, -2, 0, 9, 12), -2), ((200, 100, 0, 300, 400), 0)]) def test_min(data, expected): val = algo.min(data) assert val == expected @pytest.mark.parametrize("data, expected", [((2, 3, 1, 4, 6), 6), ((5, -2, 0, 9, 12), 12), ((200, 100, 0, 300, 400), 400)]) def test_max(data, expected): val = algo.max(data) assert val == expected ``` 在示例中,我们使用多个输入数据测试这两个函数。 ```py @pytest.mark.parametrize("data, expected", [((2, 3, 1, 4, 6), 1), ((5, -2, 0, 9, 12), -2), ((200, 100, 0, 300, 400), 0)]) def test_min(data, expected): val = algo.min(data) assert val == expected ``` 我们将两个值传递给测试函数:数据和期望值。 在我们的例子中,我们用三个数据元组测试`min()`函数。 ```py $ pytest parametrized.py ================================================= test session starts ================================================= platform win32 -- Python 3.7.0, pytest-5.0.1, py-1.8.0, pluggy-0.12.0 rootdir: C:\Users\Jano\Documents\pyprogs\pytest collected 6 items parametrized.py ...... [100%] ============================================== 6 passed in 0.03 seconds =============================================== ``` Pytest 输出告知有六次运行。 ## Pytest 夹具 测试需要在一组已知对象的背景下进行。 这组对象称为测试夹具。 `algo.py` ```py def sel_sort(data): if not isinstance(data, list): vals = list(data) else: vals = data size = len(vals) for i in range(0, size): for j in range(i+1, size): if vals[j] < vals[i]: _min = vals[j] vals[j] = vals[i] vals[i] = _min return vals ... ``` 对于此示例,我们向`algo.py`模块添加了一个选择排序算法。 `fixtures.py` ```py #!/usr/bin/env python3 import algo import pytest @pytest.fixture def data(): return [3, 2, 1, 5, -3, 2, 0, -2, 11, 9] def test_sel_sort(data): sorted_vals = algo.sel_sort(data) assert sorted_vals == sorted(data) ``` 我们用夹具测试选择排序。 ```py @pytest.fixture def data(): return [3, 2, 1, 5, -3, 2, 0, -2, 11, 9] ``` 我们的测试装置仅返回一些测试数据。 请注意,我们通过其名称引用此灯具:`data`。 ```py def test_sel_sort(data): sorted_vals = algo.sel_sort(data) assert sorted_vals == sorted(data) ``` 在`test_sel_sort()`函数中,我们将数据夹具作为函数参数传递。 ```py $ pytest fixtures.py ================================================= test session starts ================================================= platform win32 -- Python 3.7.0, pytest-5.0.1, py-1.8.0, pluggy-0.12.0 rootdir: C:\Users\Jano\Documents\pyprogs\pytest collected 1 item fixtures.py . [100%] ============================================== 1 passed in 0.02 seconds =============================================== ``` 这是输出。 ## Pytest 布局 Python 测试可以多种方式组织。 测试可以集成在 Python 包中,也可以放在包外。 ### 综合测试 接下来,我们展示如何在 Python 包中运行测试。 ```py setup.py utils │ algo.py │ srel.py │ __init__.py │ └───tests algo_test.py srel_test.py __init__.py ``` 我们有这种包装布局。 测试与包一起位于`tests`子目录中。 `setup.py` ```py #!/usr/bin/env python3 from setuptools import setup, find_packages setup(name="utils", packages=find_packages()) ``` 这是`setup.py`。 `utils/algo.py` ```py def sel_sort(data): if not isinstance(data, list): vals = list(data) else: vals = data size = len(vals) for i in range(0, size): for j in range(i+1, size): if vals[j] < vals[i]: _min = vals[j] vals[j] = vals[i] vals[i] = _min return vals def max(values): _max = values[0] for val in values: if val > _max: _max = val return _max def min(values): _min = values[0] for val in values: if val < _min: _min = val return _min ``` 这是`algo.py`文件。 `utils/srel.py` ```py def is_palindrome(val): return val == val[::-1] ``` 我们还有另一个模块,其中包含一个测试单词是否为回文的函数。 `tests/algo_test.py` ```py #!/usr/bin/env python3 import utils.algo import pytest @pytest.fixture def data(): return [3, 2, 1, 5, -3, 2, 0, -2, 11, 9] def test_sel_sort(data): sorted_vals = utils.algo.sel_sort(data) assert sorted_vals == sorted(data) def test_min(): values = (2, 3, 1, 4, 6) val = utils.algo.min(values) assert val == 1 def test_max(): values = (2, 3, 1, 4, 6) val = utils.algo.max(values) assert val == 6 ``` 这些是`utils.algo`模块的测试。 注意,我们使用完整的模块名称。 `tests/srel_test.py` ```py #!/usr/bin/env python3 import utils.srel import pytest @pytest.mark.parametrize("word, expected", [('kayak', True), ('civic', True), ('forest', False)]) def test_palindrome(word, expected): val = utils.srel.is_palindrome(word) assert val == expected ``` 这是对`is_palindrome()`函数的测试。 `utils/__init__.py` `utils/tests/__init__.py` 两个`__init__.py`文件均为空。 ```py $ pytest --pyargs utils ================================================= test session starts ================================================= platform win32 -- Python 3.7.0, pytest-5.0.1, py-1.8.0, pluggy-0.12.0 rootdir: C:\Users\Jano\Documents\pyprogs\pytest\structure collected 6 items utils\tests\algo_test.py ... [ 50%] utils\tests\srel_test.py ... [100%] ============================================== 6 passed in 0.06 seconds =============================================== ``` 我们使用`pytest --pyargs utils`命令运行测试。 ### 外部测试 下一个示例显示了应用源布局,其中测试未集成在包内。 ```py setup.py src └───utils │ algo.py │ srel.py tests algo_test.py srel_test.py ``` 在这种布局中,我们在源代码树之外进行测试。 请注意,不需要`__init__.py`文件。 ```py $ set PYTHONPATH=src $ pytest ``` 我们设置`PYTHONPATH`并运行 Pytest。 在本教程中,我们介绍了 Python Pytest 库。 您可能也对以下相关教程感兴趣: [Django 电子邮件教程](/django/email/), [Python Jinja 教程](/python/jinja/)和 [Python 教程](/lang/python/),或列出[所有 Python 教程](/all/#python)。