This document outlines the best practices and conventions for writing unit tests in this project. We use pytest as our primary testing framework.
test_, for example, test_my_module.py.test_, for example, def test_my_function():.resource.test/pytests directory, mirroring the structure of the code you are testing. For example, tests for factory/core/Objects.py should go in resource.test/pytests/factory.core/test_Objects.py.pytest Features in UseFixtures are used to provide a fixed baseline upon which tests can reliably and repeatedly execute.
@pytest.fixture: We use fixtures to set up objects and resources that are needed by multiple tests.function, class, module, or session). We commonly use scope="module" to create a single instance of a resource for all tests in a module.Example:
import pytest
from my_module import MyClass
@pytest.fixture(scope="module")
def my_class_instance():
"""Provides a cached instance of MyClass for the test module."""
return MyClass()
def test_something(my_class_instance):
assert my_class_instance.do_something() == "expected_result"
The capfd fixture is used to capture output sent to stdout and stderr.
Example:
def test_my_function_prints_hello(capfd):
my_function_that_prints()
captured = capfd.readouterr()
assert "hello" in captured.out
We use monkeypatch to modify or replace functions, methods, or objects during tests. This is essential for isolating the code under test from its dependencies.
Example:
def test_my_function_with_mock(monkeypatch):
# Mock a function that returns a specific value
monkeypatch.setattr("my_module.some_function", lambda: "mock_value")
assert my_function() == "mock_value"
To test that a function raises an exception, use pytest.raises.
Example:
import pytest
def test_my_function_raises_error():
with pytest.raises(ValueError):
my_function_that_raises_value_error()
To run all tests, execute the run_tests.sh script from the project root.
./run_tests.sh