The Test Interface
The single most important pattern in a pytest-f3ts plan is the test interface: one class that owns all access to your hardware and the device under test (DUT), exposed to tests as a session-scoped fixture.
Why a dedicated interface class
- Open once, not per test. Connecting to instruments and the DUT is slow. A session-scoped fixture opens the connection once for the whole run and closes it at the end.
- Tests stay readable. Tests call
interface.measure_rail("5v0"), not raw serial/VISA calls. Swapping hardware or mocking for offline runs only touches one file.
The interface class
Put hardware access in interface.py:
import logging
logger = logging.getLogger(__name__)
class TestInterface:
"""Owns all hardware access for the test plan."""
def __init__(self):
# Open serial ports, VISA/SCPI instruments, GPIO expanders, etc.
# Anything that raises here will fail fixture setup loudly — which is
# what you want if the bench isn't ready.
self._open = True
def measure_rail(self, name: str) -> float:
"""Return a measured rail voltage in volts."""
...
def close(self):
"""Close ports / power down the DUT."""
self._open = FalseExposing it as a fixture
In conftest.py, wrap the class in a session-scoped fixture and register teardown with addfinalizer:
import pytest
from interface import TestInterface
@pytest.fixture(scope="session")
def interface(request):
dut = TestInterface()
request.addfinalizer(dut.close) # runs even if a test fails
return dutTests then just ask for interface:
def test_5v0_rail(interface, test_config, record_property):
from pytest_f3ts.utils import log_vars
meas = interface.measure_rail("5v0")
log_vars(record_property)
assert test_config.min_limit <= meas <= test_config.max_limitRunning offline without hardware
For development, give the interface a mock implementation that returns deterministic values, so the whole plan runs with nothing connected. The Starter Test Plan does exactly this — its interface.py returns fixed nominal readings, so pytest -p f3ts passes on any machine.
Multiple interfaces
Large plans often have several: a power/measurement interface, an SSH or serial console to the DUT, an instrument driver. Each can be its own class and its own fixture. Keep each one focused on a single transport or instrument.