如何使用假设的复合策略执行Python函数?



我正在尝试执行一个用 Hypothesis 的@strategy.composite装饰器装饰的函数。

我知道我可以使用@given装饰器测试函数,例如 -

from hypothesis import given
from hypothesis import strategies as st
@given(st.integers(min_value=1))
def test_bar(x):
assert x > 0

使用 pytest 使用 -pytest <filename.py>.

但是在带有@strategy.composite装饰器的函数的情况下,例如 -

from hypothesis import strategies as st
from hypothesis import given
import pytest
@st.composite
def test_foo(draw):
arg1 = draw(st.integers(min_value=1))
arg2 = draw(st.lists(st.integers(), min_size=arg1, max_size=arg1))
print(arg1, " ", arg2)
assert(len(arg2) == arg1)

我无法以类似的方式执行测试.
使用 pytest 时,我无法执行测试(使用python执行 python 文件不执行任何操作( -

[reik@reik-msi tests]$ pytest testhypo.py
==================================== test session starts ====================================
platform linux -- Python 3.8.3, pytest-5.4.3, py-1.8.1, pluggy-0.13.1
rootdir: /home/reik/tests
plugins: hypothesis-5.16.0, lazy-fixture-0.6.3
collected 1 item                                                                            
testhypo.py F                                                                         [100%]
========================================= FAILURES ==========================================
_________________________________________ test_foo __________________________________________
item = <Function test_foo>
@pytest.hookimpl(hookwrapper=True)
def pytest_runtest_call(item):
if not hasattr(item, "obj"):
yield
elif not is_hypothesis_test(item.obj):
# If @given was not applied, check whether other hypothesis
# decorators were applied, and raise an error if they were.
if getattr(item.obj, "is_hypothesis_strategy_function", False):
>               raise InvalidArgument(
"%s is a function that returns a Hypothesis strategy, but pytest "
"has collected it as a test function.  This is useless as the "
"function body will never be executed.  To define a test "
"function, use @given instead of @composite." % (item.nodeid,)
)
E               hypothesis.errors.InvalidArgument: testhypo.py::test_foo is a function that returns a Hypothesis strategy, but pytest has collected it as a test function.  This is useless as the function body will never be executed.  To define a test function, use @given instead of @composite.
/usr/lib/python3.8/site-packages/hypothesis/extra/pytestplugin.py:132: InvalidArgument
================================== short test summary info ==================================
FAILED testhypo.py::test_foo - hypothesis.errors.InvalidArgument: testhypo.py::test_foo is...
===================================== 1 failed in 0.06s =====================================

我尝试添加函数调用test_foo()但遇到了相同的错误。

然后我尝试在函数上方添加@given并得到不同的错误 -

========================================== ERRORS ===========================================
________________________________ ERROR at setup of test_foo _________________________________
file /usr/lib/python3.8/site-packages/hypothesis/core.py, line 903
def run_test_as_given(test):
E       fixture 'test' not found
>       available fixtures: cache, capfd, capfdbinary, caplog, capsys, capsysbinary, doctest_namespace, monkeypatch, pytestconfig, record_property, record_testsuite_property, record_xml_attribute, recwarn, tmp_path, tmp_path_factory, tmpdir, tmpdir_factory
>       use 'pytest --fixtures [testpath]' for help on them.
/usr/lib/python3.8/site-packages/hypothesis/core.py:903
================================== short test summary info ==================================
ERROR testhypo.py::test_foo

如果我这样做@given()- 注意额外的大括号,相反,我得到另一个错误 -

========================================= FAILURES ==========================================
_________________________________________ test_foo __________________________________________
arguments = (), kwargs = {}
def wrapped_test(*arguments, **kwargs):
>       raise InvalidArgument(message)
E       hypothesis.errors.InvalidArgument: given must be called with at least one argument
/usr/lib/python3.8/site-packages/hypothesis/core.py:234: InvalidArgument
================================== short test summary info ==================================
FAILED testhypo.py::test_foo - hypothesis.errors.InvalidArgument: given must be called wit...

我尝试将代码包装在另一个函数中 -

from hypothesis import strategies as st
from hypothesis import given
import pytest
def demo():
@st.composite
def test_foo(draw):
arg1 = draw(st.integers(min_value=1))
arg2 = draw(st.lists(st.integers(), min_size=arg1, max_size=arg1))
print(arg1, " ", arg2)
assert(len(arg2) == arg1)

但这也没有用——

[reik@reik-msi tests]$ python testhypo.py
[reik@reik-msi tests]$ pytest testhypo.py
==================================== test session starts ====================================
platform linux -- Python 3.8.3, pytest-5.4.3, py-1.8.1, pluggy-0.13.1
rootdir: /home/reik/tests
plugins: hypothesis-5.16.0, lazy-fixture-0.6.3
collected 0 items                                                                           
=================================== no tests ran in 0.00s ===================================

(我还尝试将demo函数调用放在文件末尾,但这并没有以任何方式改变测试行为(

假设快速入门指南说调用函数会起作用,但它显然不起作用。 (公平地说,文档没有指定如何使用@composite运行测试(

如何测试用@strategy.composite装饰的函数?我不必使用 pytest - 我宁愿实际上不必使用它,但这似乎是测试函数(用@given装饰(的最简单方法,所以我决定走这条路。

@st.composite

是一个帮助函数,用于定义自定义策略,而不是测试。

您尝试执行的操作可以通过使用@givenst.data()来完成:

@given(st.data())
def test_foo(data):
x = data.draw(st.integers())
...

https://hillelwayne.com/post/property-testing-complex-inputs/很好地概述了如何使用这些技术。

我遇到了同样的问题。这是一个使用@composite的最小且完整的工作示例。

@dataclass
class Container():
id: int
value: str
@st.composite
def generate_containers(draw):
_id = draw(st.integers())
_value = draw(st.characters())
return Container(id=_id, value=_value)
@given(generate_containers())
def test_container(container):
assert isinstance(container, Container)
assert isinstance(container.id, int)
assert isinstance(container.value, str)

最新更新