跳转到主要内容

Pytest插件,用于测试函数幂等性。

项目描述

pytest-idempotent

Python 3.7+ PyPI version Build Status GitHub license codecov Downloads

Pytest插件,用于测试函数的幂等性。

用法

pip install pytest-idempotent

文档

假设我们有一个以下函数,我们(错误地)假设它是幂等的。我们如何编写测试呢?

首先,我们可以用装饰器标记这个函数

# abc.py
from pytest_idempotent import idempotent  # or use your own decorator! See below.

@idempotent
def func(x: list[int]) -> None:
    x += [9]

注意:这个函数不是幂等的,因为每次在相同的列表x上调用它都会使x的大小增加1。为了是幂等的,我们应该能够多次运行func而没有任何不良影响。

我们可以按照以下方式编写这个函数的幂等性测试

# tests/abc_test.py
import pytest

@pytest.mark.idempotent
def test_func() -> None:
    x: list[int] = []

    func(x)

    assert x == [9]

添加@pytest.mark.idempotent标记会自动将此测试分割成两个 - 一个测试常规行为,另一个测试函数是否可以在没有不良影响的情况下被调用两次。

❯❯❯ pytest

================= test session starts ==================
platform darwin -- Python 3.9.2, pytest-6.2.5
collected 2 items

tests/abc_test.py .F                     [100%]

=====================  FAILURES ========================
------------- test_func[idempotency-check] -------------

    @pytest.mark.idempotent
    def test_func() -> None:
        x: list[int] = []

        func(x)

>       assert x == [9]
E       assert [9, 9] == [9]
E         Left contains one more item: 9
E         Use -v to get the full diff

tests/abc_test.py:19: AssertionError
=============== short test summary info ================
FAILED tests/abc_test.py::test_func[idempotency-check]
  - assert [9, 9] == [9]
============= 1 failed, 1 passed in 0.16s ==============

工作原理

幂等性是一个难以强制的模式。为了解决这个问题,pytest-idempotent采用以下方法

  • 引入一个装饰器,@idempotent,用于函数。

    • 这个装饰器作为一个视觉辅助。如果这个装饰器在代码库中常用,考虑新和现有函数的幂等性就更容易了。
    • 在运行时,这个装饰器是一个空操作。
    • 在测试时,如果启用了这个功能,我们将对所有测试用例中的装饰器函数使用相同的参数运行两次。
    • 我们还可以通过函数装饰器的额外参数断言第二次运行返回相同的结果:@idempotent(equal_return=True)
  • 对于使用 @pytest.mark.idempotent 标记的所有测试,我们将每个测试运行两次:一次正常运行,一次调用装饰函数两次。

    • 两次运行都需要通过所有断言。
    • 我们返回第一次的结果,因为第一次运行将完成处理。第二次将返回完全相同的结果或无操作。
    • 要禁用测试或测试组的幂等性测试,请添加 Pytest 标记: @pytest.mark.idempotent(enabled=False)

强制执行测试使用 @pytest.mark.idempotent

默认情况下,任何调用 @idempotent 函数的测试都必须也带有标记 @pytest.mark.idempotent

要禁用测试或测试组的幂等性测试,请使用: @pytest.mark.idempotent(enabled=False),或向项目中添加以下配置

def pytest_idempotent_enforce_tests() -> bool:
    return False

要禁用特定函数的强制幂等性测试,也可以将标志传递给装饰器

# abc.py
from pytest_idempotent import idempotent

@idempotent(enforce_tests=False)
def func() -> None:
    return

或者,您可以通过在 conftest.py 中添加来根据测试名称自动添加标记

# conftest.py
def pytest_collection_modifyitems(items):
    for item in items:
        if "idempotent" in item.nodeid:
            item.add_marker(pytest.mark.idempotent)

@idempotent 装饰器

默认情况下,@idempotent 装饰器在运行时不会做任何事情。我们不想在生产代码中增加测试的额外开销。

from typing import Any, Callable, TypeVar

_F = TypeVar("_F", bound=Callable[..., Any])


def idempotent(func: _F) -> _F:
    """
    No-op during runtime.
    This marker allows pytest-idempotent to override the decorated function
    during test-time to verify the function is idempotent.
    """
    return func

要使用自己的 @idempotent 装饰器,您可以在 conftest.py 中覆盖 pytest_idempotent_decorator 函数,以返回您的实现模块路径。

# conftest.py
# Optional: you can define this to ensure the plugin is correctly installed
pytest_plugins = ["pytest_idempotent"]


def pytest_idempotent_decorator() -> str:
    # This links to my custom implementation of @idempotent.
    return "src.utils.idempotent"

项目详情


下载文件

下载适用于您的平台的文件。如果您不确定选择哪个,请了解更多关于 安装包 的信息。

源分布

pytest_idempotent-1.3.1.tar.gz (8.7 kB 查看哈希值)

上传时间

构建分布

pytest_idempotent-1.3.1-py3-none-any.whl (8.8 kB 查看哈希值)

上传时间 Python 3

由以下机构支持

AWS AWS 云计算和安全赞助商 Datadog Datadog 监控 Fastly Fastly CDN Google Google 下载分析 Microsoft Microsoft PSF 赞助商 Pingdom Pingdom 监控 Sentry Sentry 错误记录 StatusPage StatusPage 状态页面