14. Testing Strategy (pytest)
Combine unit, integration, and property-based tests; isolate effects and assert logs/metrics where it matters.
Question: What is property-based testing and why is it useful?
Answer: Property-based testing is a technique where you define general properties or invariants that your code should satisfy, and a library (like hypothesis
for Python) generates a wide range of random test cases to try and falsify those properties. It is extremely effective at finding subtle edge cases that developers might miss when writing example-based tests.
Question: How do
pytest
fixtures improve testing?
Answer: Fixtures provide a modular and reusable way to manage the setup and teardown of test dependencies, such as database connections, temporary files, or complex objects. They are dependency-injected into test functions, making tests cleaner, more readable, and easier to maintain compared to older xUnit-style setUp
/tearDown
methods. Fixtures can also have different scopes (function, class, module, session), which allows for efficient resource management.
import pytest
import json
# `tmp_path` is a built-in pytest fixture that provides a temporary directory
@pytest.fixture
def config_file(tmp_path):
config_path = tmp_path / "config.json"
config_data = {"host": "localhost", "port": 5432}
config_path.write_text(json.dumps(config_data))
return config_path
def test_read_config(config_file):
# The `config_file` fixture is injected here by pytest
data = json.loads(config_file.read_text())
assert data["host"] == "localhost"
assert data["port"] == 5432
Question: How do you parametrize tests effectively?
Answer: Use @pytest.mark.parametrize
to run the same test logic over multiple inputs and expected outputs.
Explanation: Improves coverage and reduces duplication.
@pytest.mark.parametrize("a,b,s", [(1,2,3),(0,0,0),(-1,1,0)])
def test_add(a,b,s):
assert add(a,b) == s
Question: How do you test async code?
Answer: Use pytest-asyncio
or anyio
with an event loop fixture; avoid real sleeps and I/O.
Explanation: Use fakes/mocks and time control.
import pytest, asyncio
@pytest.mark.asyncio
async def test_async():
assert await coro() == 42
Question: How do you isolate external dependencies in tests?
Answer: Use monkeypatch
/mocker
to stub environment, time, and network calls.
Explanation: Promotes deterministic, fast tests.