---
tags: technical, faq, python
date: 2016-08-09 10:00
title: How do I use pytest fixtures with Hypothesis?
author: drmaciver
---

[pytest](http://doc.pytest.org/en/latest/) is a great test runner, and is the one
Hypothesis itself uses for testing (though Hypothesis works fine with other test
runners too).

It has a fairly elaborate [fixture system](http://doc.pytest.org/en/latest/fixture.html),
and people are often unsure how that interacts with Hypothesis. In this article we'll
go over the details of how to use the two together.

<!--more-->

Mostly, Hypothesis and pytest fixtures don't interact: Each just ignores the other's
presence.

When using a @given decorator, any arguments that are not provided in the @given
will be left visible in the final function:

```python
from inspect import signature

from hypothesis import given, strategies as st


@given(a=st.none(), c=st.none())
def test_stuff(a, b, c, d):
    pass


print(signature(test_stuff))
```

This then outputs the following:

```
<Signature (b, d)>
```

We've hidden the arguments 'a' and 'c', but the unspecified arguments 'b' and 'd'
are still left to be passed in. In particular, they can be provided as pytest
fixtures:

```python
from pytest import fixture

from hypothesis import given, strategies as st


@fixture(scope="module")
def stuff():
    return "kittens"


@given(a=st.none())
def test_stuff(a, stuff):
    assert a is None
    assert stuff == "kittens"
```

Note the explicit `scope="module"`: pytest fixtures default to function scope,
which Hypothesis rejects for `@given` tests - see the end of this article for
why, and what to do about it.

This also works if we want to use @given with positional arguments:

```python
from pytest import fixture

from hypothesis import given, strategies as st


@fixture(scope="module")
def stuff():
    return "kittens"


@given(st.none())
def test_stuff(stuff, a):
    assert a is None
    assert stuff == "kittens"
```

The positional argument fills in from the right, replacing the 'a'
argument and leaving us with 'stuff' to be provided by the fixture.

Personally I don't usually do this because I find it gets a bit
confusing - if I'm going to use fixtures then I always use the named
variant of given. There's no reason you *can't* do it this way if
you prefer though.

@given also works fine in combination with parametrized tests:

```python
import pytest

from hypothesis import given, strategies as st


@pytest.mark.parametrize("stuff", [1, 2, 3])
@given(a=st.none())
def test_stuff(a, stuff):
    assert a is None
    assert 1 <= stuff <= 3
```

This will run 3 tests, one for each value for 'stuff'.

There is one unfortunate feature of how this interaction works though: In pytest
you can declare fixtures which do set up and tear down per function. These will
"work" with Hypothesis, but they will run once for the entire test function
rather than once for each time given calls your test function. So the following
will fail:

```python
from pytest import fixture

from hypothesis import given, strategies as st

counter = 0


@fixture(scope="function")
def stuff():
    global counter
    counter = 0


@given(a=st.none())
def test_stuff(a, stuff):
    global counter
    counter += 1
    assert counter == 1
```

The counter will not get reset at the beginning of each call to the test function,
so it will be incremented each time and the test will start failing after the
first call.

*Update, 2026: the rest of this article has been rewritten, because Hypothesis
now detects this problem for you.*

Rather than letting a test like the one above quietly do the wrong thing,
Hypothesis raises a health check error whenever a test using `@given` requests
a function-scoped fixture - including pytest fixtures declared with no explicit
scope, since function scope is the default:

```
FailedHealthCheck: 'tests.py::test_stuff' uses a function-scoped fixture 'stuff'.

Function-scoped fixtures are not reset between inputs generated by
`@given(...)`, which is often surprising and can cause subtle test bugs.
```

So instead of a silently unsound test, you get an immediate error and a choice
about how to proceed.

If you need set up and tear down for each generated input, do it inside the
test function, for example with a context manager:

```python
from contextlib import contextmanager

from hypothesis import given, strategies as st


@contextmanager
def fresh_stuff():
    yield "kittens"  # set up before this line, and tear down after


@given(a=st.none())
def test_stuff(a):
    with fresh_stuff() as stuff:
        assert a is None
        assert stuff == "kittens"
```

If the fixture value is safe to reuse across inputs, declare it with a wider
scope such as `module` or `session` and use it exactly as shown earlier in
this article.

And if running the fixture once per test function really is what you want,
tell Hypothesis that you've thought about this and it's OK:

```python
from hypothesis import HealthCheck, given, settings, strategies as st


@settings(suppress_health_check=[HealthCheck.function_scoped_fixture])
@given(a=st.none())
def test_stuff(a, stuff):
    assert a is None
```

Running fixtures once per generated input would [require changes on the pytest
side as well as the Hypothesis side](https://github.com/pytest-dev/pytest/issues/916),
and still isn't supported - but with the health check to catch mistakes and the
patterns above to express each intent, in practice this is no longer a problem.
