plesty init mock-test
Adds the hardware-free test gate d1 requires to an existing device module.
Unlike plesty init field-test, it asks nothing.
cd plesty-pm100d
plesty init mock-test # writes tests/test_mock_pipeline.py
plesty init mock-test --force # regenerate over its own previous output
The field-test interview exists because every one of its questions is a safety judgement about a real instrument. Nothing in the mock pipeline can move a stage or fire an exposure, and everything it needs is either declared by the device or settled by trying it:
Source |
What it gives |
|---|---|
the device’s |
the parameters and operations, read through the same reader the field test uses |
the package name |
the module and the import |
a construction probe |
how to reach the device without hardware |
The probe
The probe is the design. A device module is hardware-free in one of
several ways — address="mock" selects an in-memory simulator in one
reference module, use_mock_solver=True does it in the other — and which one
applies is knowable by constructing the device and looking. Each candidate is
verified the way the gates will verify it: connect, read is_operatable,
call identity(), and call check_errors(), which must return a list — empty
on a fresh device. A strategy is written into the file only once it has passed
the checks the file will make, which is why a generated test that gets written
is a generated test that passes those checks.
When neither applies, the last resort is the module’s own DocDevice — the
hardware-free construction gate d3 already requires. A module scaffolded by
plesty init device exports it as partial(Device, id=...), and because
DevicePipeline constructs from a class, the file passes Device and
forwards the partial’s own arguments:
PIPELINE = DevicePipeline(Device, *DocDevice.args, **DocDevice.keywords)
A DocDevice that is neither a class nor a partial of Device is refused
with that reason.
Where no strategy works the command refuses and lists what it tried. It does
not fall back to asking: a developer handed a question the probe could not
answer would be guessing at the same thing, and a file built on a guess looks
complete and tests less than it claims. Give the device a hardware-free path —
address="mock" is the convention, and
plesty.lib.sim.demo_device.DemoDevice is the reference implementation of it —
then run the command again.
The probe covers three of the eight gates. On a fresh scaffold the file is
written and gate 2 (parameter key resolution) still fails until the device
declares its schema — the first of the next steps plesty init device prints.
The generated file
The generated file is short, because run_mock_pipeline() runs all eight
gates and raises with everything that failed:
from plesty.lib.test.device_pipeline import DevicePipeline
from plesty.pm100d import Device
PIPELINE = DevicePipeline(Device, address="mock")
def test_mock_pipeline() -> None:
"""Run the eight mock gates and fail with everything that broke."""
PIPELINE.run_mock_pipeline()
No schema path appears in it. The gates read what the device declares at run time, so nothing here restates a schema and nothing goes stale when the device gains a parameter.
The file is always tests/test_mock_pipeline.py, never tests/test_<module>.py
— that is where a module’s hand-written unit tests already live, and one
reference module keeps 487 lines of them. --force regenerates over this
command’s own output and refuses anything else, checked by a marker in the
file, so a regeneration cannot destroy work.