Pytest on TofuPilot

Last updated on May 21, 2026

pytest is a code-first Python test framework built around test_* functions and assert statements, with hardware setup handled via fixtures.

With TofuPilot, you can deploy pytest suites to your stations via Git push and stream live test data to both the kiosk and the dashboard, with zero configuration.

Getting started

To get started with pytest on TofuPilot:

  • Clone our pytest starter template to your favorite Git provider and deploy it on TofuPilot.
  • If you have a pytest suite, push it to your Git provider and import it from the New Procedure wizard.

Integration

The TofuPilot CLI runs your pytest suite natively under an embedded plugin and streams tests, asserts, and logs to the dashboard.

test_supply.py
def test_supply_voltage():
    voltage = read_voltage()
    assert 4.8 <= voltage <= 5.2, "Supply voltage [V]"

Tests

In pytest, every collected test_* function is one unit of execution. TofuPilot maps each test to a phase row.

pytestTofuPilotNotes
test function namenameCapped at 200 chars.
test outcomeoutcomepassedPASS, failedFAIL, skippedSKIP, errors → ERROR.
test docstringdocstringCapped at 50000 chars.
call timestartedAt / endedAtWall-clock around the call phase only.
pytest.mark.parametrizeretryCountEach parametrize instance is a separate phase row, not a retry.

Measurements

The plugin parses each test's AST at collection time and promotes recognized assert patterns to typed measurements with limits and a runtime-captured value.

test_temperature.py
def test_temperature():
    temp = read_temperature()
    assert 20 <= temp <= 80, "Case temperature [°C]"
Assert patternTofuPilot
assert lo <= x <= hiNumeric measurement with >= / <= validator entries
assert x >= lo / <= hi / > lo / < hiNumeric measurement, single bound
assert x == n / != n (numeric)Numeric measurement, equality
assert x == pytest.approx(n, ...)Numeric measurement, equality with tolerance
assert s == "value" / != "value"String measurement, equality
assert s in [...] / not in [...]String measurement, set membership
assert b is True / is False / == True / == FalseBoolean measurement
Anything elsenot persisted — phase still records pass/fail

The assert message becomes the measurement docstring. Append [unit] to set the units field on numeric measurements.

Logs

Standard Python logging records flow through TofuPilot. The connector attaches a handler to the root logger at session start, so any module-level call is captured.

test_calibration.py
import logging

def test_calibration():
    logging.info("Calibration started")
    assert calibrate() == "OK"
Python LogRecordTofuPilotNotes
levelnamelevelDEBUG, INFO, WARNING, ERROR, CRITICAL.
createdtimestampEpoch seconds → ISO 8601 timestamp.
messagemessageCapped at 50000 chars.
pathnamesourceFileCapped at 200 chars.
linenolineNumber
name (logger name)not persisted

Logs are stored at the run level; per-test association is not preserved.

Run metadata

pytest has no built-in concept of a unit under test. TofuPilot reads defaults from pyproject.toml to identify the run:

pyproject.toml
[tool.tofupilot]
serial_number = "SN-0001"
part_number = "PCB01"
revision_number = "A"
batch_number = "2024-001"
auto_identify = false

When auto_identify is false (default), the CLI prompts the operator for the serial number on stdin before collection. When true, the defaults are used directly — the right choice for stations where a barcode scanner fills the serial in advance.

Fixtures

pytest fixtures run as-is in Python — setup, teardown, scoping, and dependency injection work unchanged. The dashboard does not surface fixture instances or lifecycle events; only the data emitted from inside a test (measurements, logs) is captured.

Offline upload

When the bench can lose connectivity, the CLI queues runs locally and uploads them when the network comes back. Each queued run keeps its original timestamp, so analytics stay accurate even when uploads land hours later. See tofupilot queue.

Unsupported features

The following pytest features run as-is in Python, but TofuPilot does not surface them on the dashboard.

FeatureStatus
pytest.mark.parametrizeEach instance becomes a separate phase row; parametrize metadata is not persisted.
pytest.mark.skipif / xfailHonored by pytest; skipped tests record as SKIP, xfail outcomes collapse to standard pass/fail.
Custom markersRun as-is; not persisted on the phase.
Fixtures (@pytest.fixture)Run as-is; no dashboard surface.
conftest.py hooksHonored by pytest; not surfaced.
pytest plugins (pytest-xdist, pytest-html, ...)Load as normal; TofuPilot does not consume their output.
AttachmentsNo pytest helper; attach via the SDK directly if needed.
Operator promptsNot supported. Use OpenHTF or the TofuPilot Framework for live operator UI.
Multi-dim measurements with per-axis validatorsTofuPilot Framework only.

How is this guide?

On this page