Pytest插件,用于测试函数幂等性。
项目描述
pytest-idempotent
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 的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 0ba6a9b9813cd06f377555c79b871c7a03fe81517d746ed0cfce0373ec7d2f9b |
|
MD5 | 081b17ed1946bbe50fd6b8497724ab64 |
|
BLAKE2b-256 | 4de201f4aed845fb34a0ff49922d8b0cc5bd8ead835922887a03e31da823706d |
pytest_idempotent-1.3.1-py3-none-any.whl 的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | a66077cbcdef59b6b2b25347367bc9bf8903ac1ab2641efa0bbcf09be5a7c119 |
|
MD5 | ff5fe8ccc20bae0b9a02e2bced684f32 |
|
BLAKE2b-256 | 069daa20b5c3df881b66f068e5f39c7654de919ce086810375c9748d242bef5e |