eolas/zk/Pytest_fixtures.md

93 lines
2.2 KiB
Markdown
Raw Normal View History

2026-01-08 19:44:37 +00:00
---
tags: [python, pytest]
---
Fixtures are a way to provide data or state to your tests. Typically, although
not exclusively, for processes that you want to reuse accross different `test_`
functions. They are defined at the "arrange" stage of testing.
## Example: testing class methods under test
```py
class Person:
def __init__(self, name):
self.name = name
def print_name(self):
return f"Your name is {self.name}"
```
To create a fixture of this class:
```py
@pytest.fixture
def my_person():
person = new Person('Thomas')
return person.name()
test_print_name(my_person):
assert(my_person) == 'Thomas'
```
> Note we define our fixture and then inject it into our test function.
> Functions request fixtures they require by declaring them as arguments.
Alternatively you could just return the class from the fixture and test the
methods individually within the test function.
## Integrating with `@patch` to provide mock fixtures
Say we wanted to mock reading a JSON file.
We could create a fixture:
```py
@pytest fixture
def raw_json():
return json.dumps({"key": "value"})
```
And pass it in to the mock of the global `open` method:
```py
from unittest.mock import mock_open, patch
def test_json_parsing(raw_json):
with patch("builtins.open", mock_open(read_data=raw_json))
# Then assert etc
```
This fixture could then be re-used to test any other method that relies on
incoming JSON from a file.
## Example: setup and teardown - before each and after each
Fixtures can be leveraged to setup 'before each...' and 'after each...' logic:
```py
@pytest.fixture(scope="function")
def setup():
os.environ["POCKET_LAMBDA_ENDPOINT"] = "https://some_endpoint.com/{article_type}"
yield
del os.environ["POCKET_LAMBDA_ENDPOINT"]
```
Here `yield` is a placeholder for the tests that run in between the setup and
teardown.
We use `scope="function"` to signal that this will run before/after any tests
that inject the fixture.
Then to specify the units that will run as the `yield` we just inject `setup`:
```py
def some_function(setup_function):
pass
```
2026-01-11 18:27:51 +00:00
## Example: setting up mocks before every test
We can combine the