As the documentation and this article state, it should be possible to use hypothesis strategies and pytest fixtures in the same test.
But executing this example code of the article:
from hypothesis import given, strategies as st
from pytest import fixture
@fixture
def stuff():
return "kittens"
@given(a=st.none())
def test_stuff(a, stuff):
assert a is None
assert stuff == "kittens"
yields the following error:
FAILED [100%]
test_with_fixture.py:9 (test_stuff)
item = <Function test_stuff>
@pytest.hookimpl(hookwrapper=True)
def pytest_runtest_call(item):
if not (hasattr(item, "obj") and "hypothesis" in sys.modules):
yield
return
from hypothesis import core
from hypothesis.internal.detection import is_hypothesis_test
core.running_under_pytest = True
if 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):
from hypothesis.errors import InvalidArgument
raise InvalidArgument(
f"{item.nodeid} 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."
)
message = "Using `@%s` on a test without `@given` is completely pointless."
for name, attribute in [
("example", "hypothesis_explicit_examples"),
("seed", "_hypothesis_internal_use_seed"),
("settings", "_hypothesis_internal_settings_applied"),
("reproduce_example", "_hypothesis_internal_use_reproduce_failure"),
]:
if hasattr(item.obj, attribute):
from hypothesis.errors import InvalidArgument
raise InvalidArgument(message % (name,))
yield
else:
from hypothesis import HealthCheck, settings
from hypothesis.internal.escalation import current_pytest_item
from hypothesis.internal.healthcheck import fail_health_check
from hypothesis.reporting import with_reporter
from hypothesis.statistics import collector, describe_statistics
# Retrieve the settings for this test from the test object, which
# is normally a Hypothesis wrapped_test wrapper. If this doesn't
# work, the test object is probably something weird
# (e.g a stateful test wrapper), so we skip the function-scoped
# fixture check.
settings = getattr(item.obj, "_hypothesis_internal_use_settings", None)
# Check for suspicious use of function-scoped fixtures, but only
# if the corresponding health check is not suppressed.
if (
settings is not None
and HealthCheck.function_scoped_fixture
not in settings.suppress_health_check
):
# Warn about function-scoped fixtures, excluding autouse fixtures because
# the advice is probably not actionable and the status quo seems OK...
# See https://github.com/HypothesisWorks/hypothesis/issues/377 for detail.
argnames = None
for fx_defs in item._request._fixturemanager.getfixtureinfo(
node=item, func=item.function, cls=None
).name2fixturedefs.values():
if argnames is None:
argnames = frozenset(signature(item.function).parameters)
for fx in fx_defs:
if fx.argname in argnames:
active_fx = item._request._get_active_fixturedef(fx.argname)
if active_fx.scope == "function":
> fail_health_check(
settings,
_FIXTURE_MSG.format(fx.argname, item.nodeid),
HealthCheck.function_scoped_fixture,
)
E hypothesis.errors.FailedHealthCheck: Function-scoped fixture 'stuff' used by 'test_with_fixture.py::test_stuff'
E
E Function-scoped fixtures are not reset between examples generated by
E `@given(...)`, which is often surprising and can cause subtle test bugs.
E
E If you were expecting the fixture to run separately for each generated example,
E then unfortunately you will need to find a different way to achieve your goal
E (e.g. using a similar context manager instead of a fixture).
E
E If you are confident that your test will work correctly even though the
E fixture is not reset between generated examples, you can suppress this health
E check to assure Hypothesis that you understand what you are doing.
E
E See https://hypothesis.readthedocs.io/en/latest/healthchecks.html for more information about this. If you want to disable just this health check, add HealthCheck.function_scoped_fixture to the suppress_health_check settings for this test.
../.venv/lib/python3.10/site-packages/_hypothesis_pytestplugin.py:250: FailedHealthCheck
I am using pytest version 7.1.2 and hypothesis version 6.47.5
What am I doing wrong?
Is there another way to use pytest fixtures and hypothesis strategies together?