Pytest的常用高级用法及示例

Pytest是Python中一种流行的测试框架,它提供了丰富的功能和灵活性,可以帮助编写高效且可维护的测试代码。除了基本的测试功能外,Pytest还有许多高级用法可以帮助更好地组织、管理和扩展测试套件。

Pytest的常用高级用法及示例

以下是一些Pytest的常用高级用法,以及相应的示例介绍:

1、参数化测试(Parametrize)

参数化测试允许在单个测试函数中运行多个测试用例,每个用例都使用不同的参数。这对于测试相似场景下的多组输入非常有用。

 import pytest

 @pytest.mark.parametrize("input,expected", [(1, 2), (2, 4), (3, 6)])
 def test_multiply_by_two(input, expected):
     assert input * 2 == expected

2、自定义标记和筛选(Custom Marking and Filtering)

可以使用自定义的标记来标识测试用例,然后使用标记来选择性地运行特定类型的测试。

import pytest

@pytest.mark.slow
def test_slow_function():
    # test implementation

@pytest.mark.skip
 def test_skipped_function():
     # test implementation

运行只有特定标记(slow)的测试:pytest -m slow

3、测试夹具(Fixtures)

夹具是一种在多个测试函数之间共享资源和设置的方法,可以减少重复的代码和提高测试的效率。

import pytest

@pytest.fixture
def setup_teardown_example():
    # setup code
    yield
    # teardown code

def test_using_fixture(setup_teardown_example):
    # test implementation

4、自定义断言(Custom Assertions)

Pytest允许编写自定义的断言函数,以便在测试中更清晰地描述预期结果。

def assert_custom_condition(result):
    assert result > 0, f"Expected result to be positive, but got {result}"

def test_custom_assertion():
    result = some_function()
    assert_custom_condition(result)

5、测试装饰器(Test Decorators)

Pytest允许编写自定义的测试装饰器来扩展测试功能,比如在测试运行前后执行额外的代码。

import pytest

def my_test_decorator(func):
    def wrapper():
        print("Before test")
        func()
        print("After test")
    return wrapper

@my_test_decorator
def test_decorated_function():
    # test implementation

6、测试参数化组合(Combining Parametrized Tests)

可以将不同的参数化测试组合在一起,以测试多个输入组合的情况。

 import pytest

 @pytest.mark.parametrize("input", [1, 2])
 @pytest.mark.parametrize("factor", [2, 3])
 def test_parametrized_combinations(input, factor):
    result = input * factor
    assert result == input * factor

7、 插件扩展(Plugin Extensions)

Pytest具有丰富的插件生态系统,允许使用现有插件或编写自定义插件来扩展测试功能。

# 使用插件:pytest-html生成测试报告
# 安装插件:pip install pytest-html
# 运行测试并生成HTML报告

pytest --html=report.html

8、命令行选项和配置文件(Command-Line Options and Configuration Files):

通过命令行选项和配置文件,可以自定义Pytest的行为,包括测试运行、输出格式、覆盖率报告等。

# 运行测试并显示详细输出
pytest -v

# 运行测试并生成覆盖率报告
pytest --cov=my_module

9、跳过测试(Skipping Tests)

有时可能需要暂时跳过某些测试,可以使用“@pytest.mark.skip”来标记这些测试。

import pytest

@pytest.mark.skip(reason="Test not ready yet")
def test_skipped_function():
    # test implementation

10、 预期异常(Expecting Exceptions)

可以使用“pytest.raises”上下文管理器来测试代码是否引发了预期的异常。

import pytest

def test_exception_handling():
    with pytest.raises(ValueError):
        # code that should raise ValueError

11、测试参数定制(Customizing Test Discovery)

通过在“pytest.ini”配置文件中定义 python_files、python_classes 和 python_functions 等,可以自定义测试文件、测试类和测试函数的命名规则。  

# pytest.ini
[pytest]
python_files = test_*.py
python_classes = Test*
python_functions = test_*

12、多进程和分布式测试(Parallel and Distributed Testing)

Pytest支持通过插件进行多进程和分布式测试,以提高测试速度。

# 运行测试并使用4个进程
pytest -n 4

# 使用pytest-xdist插件进行分布式测试
# 安装插件:pip install pytest-xdist

# 运行测试并在3台主机上分布式运行
pytest -n 3 --dist=loadscope

13、使用 pytest-xdist 进行分布式测试

pytest-xdist插件支持在多个进程或多台机器上分布式运行测试,以加速测试过程。

# 安装pytest-xdist插件
pip install pytest-xdist

# 在多个进程上分布式运行测试
pytest -n NUM_PROCESSES

# 在多台机器上分布式运行测试
pytest -n NUM_MACHINES --dist=loadscope

14、标记依赖和顺序(Marking Dependencies and Ordering)

有时,测试之间可能存在依赖关系,或者按照特定的顺序运行测试。Pytest允许使用“@pytest.mark.dependency”和“@pytest.mark.run”来实现这一点。 

import pytest

@pytest.mark.dependency()
def test_dependency_1():
    # test implementation

@pytest.mark.dependency(depends=["test_dependency_1"])
def test_dependency_2():
    # test implementation

@pytest.mark.run(order=1)
def test_first():
    # test implementation

@pytest.mark.run(order=2)
def test_second():
    # test implementation

15、预设参数(Fixture Parametrization)

可以将夹具参数化,为夹具提供不同的配置,以便在不同测试用例中使用。

import pytest

@pytest.fixture(params=[(1, 2), (2, 4), (3, 6)])
def input_output(request):
    return request.param

def test_multiply(input_output):
    input, expected = input_output
    assert input * 2 == expected

16、忽略特定Python版本(Ignoring Specific Python Versions)

使用“@pytest.mark.skipif”可以在特定Python版本上跳过测试。

import pytest
import sys

@pytest.mark.skipif(sys.version_info >= (3, 9), reason="Not supported in this version")
def test_skip_for_version():
    # test implementation

17、设置全局夹具(Global Fixtures)

如果希望多个测试文件共享同一组夹具,可以在根目录下创建一个“conftest.py”文件,定义全局夹具。

# conftest.py
import pytest

@pytest.fixture
def global_fixture():
    # setup code
    yield
    # teardown code

18、多阶段测试(Multi-Stage Testing)

对于较复杂的应用,可能需要在不同阶段执行测试,比如集成测试、端到端测试等。可以使用 “-k” 命令行选项来指定运行特定阶段的测试。

# 运行特定阶段的测试
pytest -k "integration or endtoend"

19、使用 pytest-mock 进行模拟

`pytest-mock` 插件简化了对 Python 的模拟和测试桩的使用,使得编写测试用例更加容易。

# 安装 pytest-mock 插件
pip install pytest-mock
import pytest
from unittest.mock import MagicMock

def test_using_mock(mocker):
    mock_obj = mocker.MagicMock()
    mock_obj.some_method.return_value = 42
    result = mock_obj.some_method()
    assert result == 42
    mock_obj.some_method.assert_called_once()

20、测试失败自动重试

有时测试失败可能是由于不稳定的因素导致的,可以使用 `pytest-rerunfailures` 插件来自动重试失败的测试。

# 安装 pytest-rerunfailures 插件
pip install pytest-rerunfailures

# 运行测试并自动重试失败的测试
pytest --reruns 3

21、使用 pytest-flake8 进行静态代码分析

pytest-flake8 插件可以集成“flake8”静态代码分析工具,帮助在运行测试时进行代码质量检查。

# 安装 pytest-flake8 插件
pip install pytest-flake8

# 运行测试并进行静态代码分析
pytest --flake8

这些是更多的 Pytest 高级用法,它们进一步扩展了在测试中的能力。无论是针对不同类型的应用,测试框架提供了丰富的工具和插件来帮助更有效地测试代码。



留言