Skip to content
Sarj Code Standards

prefer-pytest-fixture-contract

Expose existing abstract contracts from pytest fixtures and injected parameters.

Why

Concrete fixture exports and injected parameter annotations couple consumers to an implementation even when an existing ABC or Protocol supports the consumed operations.

Fix

Keep concrete construction in the fixture and annotate supplied instances and injected parameters with their existing ABC or Protocol. Retain a reviewed concrete annotation for implementation-specific behavior or stronger concrete guarantees.

Examples

Before — flagged A composition fixture exposes a concrete collaborator parameter
tests/conftest.py
import pytest
from abc import ABC, abstractmethod
class Store(ABC):
@abstractmethod
def read(self) -> int: ...
class SqlStore(Store):
def read(self) -> int:
return 1
class Router:
def __init__(self, store: Store) -> None:
self.store = store
@pytest.fixture
def router(store: SqlStore) -> Router:
return Router(store=store)
After — preferred The composition fixture accepts the existing collaborator contract
tests/conftest.py
import pytest
from abc import ABC, abstractmethod
class Store(ABC):
@abstractmethod
def read(self) -> int: ...
class SqlStore(Store):
def read(self) -> int:
return 1
class Router:
def __init__(self, store: Store) -> None:
self.store = store
@pytest.fixture
def router(store: Store) -> Router:
return Router(store=store)