testing.pytest_plugin¶
Pytest plugin for the raccoon sim test harness.
This module is registered as a pytest11 entry point in the raccoon
wheel, so once raccoon is installed in a project’s test environment the
fixtures below are available with no conftest boilerplate.
The three fixtures that matter:
robot: a fully wired instance of the project’s generatedsrc.hardware.robot.Robotclass, backed by the mock HAL.scene: a factory for entering araccoon.testing.sim.use_scene()context. Automatically resolves scene names against the project’s ownscenes/dir first, then raccoon’s bundled scenes.run_step: a sync callable that awaitsstep.run_step(robot)with a timeout. Tests stay sync; no pytest-asyncio dependency.
Typical usage:
from raccoon.step.motion.drive_dsl import drive_forward
from raccoon.testing.sim import pose
def test_drives_30cm(robot, scene, run_step):
scene("empty_table.ftmap", start=(20, 50, 0))
run_step(drive_forward(cm=30), robot)
assert pose().x > 45
Attributes¶
Functions¶
|
The discovered raccoon project (root, raw yml data, derived SimRobotConfig). |
|
A fresh |
|
Instantiate the project's generated Robot class. |
|
Factory that enters a |
|
Sync wrapper that awaits |
|
Bypass interpreter shutdown when the mock HAL was exercised. |
Module Contents¶
- testing.pytest_plugin.ROBOT_IMPORT_PATH = 'src.hardware.robot'¶
- testing.pytest_plugin.ROBOT_CLASS_NAME = 'Robot'¶
- testing.pytest_plugin.project_info() testing._project.ProjectInfo¶
The discovered raccoon project (root, raw yml data, derived SimRobotConfig).
Session-scoped because the project layout doesn’t change during a test run. If your tests aren’t inside a raccoon project, requesting this fixture fails with a clear error.
- testing.pytest_plugin.robot_sim_config(project_info: testing._project.ProjectInfo) testing.sim.SimRobotConfig¶
A fresh
SimRobotConfigderived from the project’s yml.Function-scoped so individual tests can mutate it (e.g. add
line_sensors) without leaking state across tests. Use this as an override hook when a test needs non-default sim geometry.
- testing.pytest_plugin.robot(project_info: testing._project.ProjectInfo) Any¶
Instantiate the project’s generated Robot class.
Skips with a helpful message if the installed raccoon wheel wasn’t built with the mock driver bundle. Uses a fresh instance per test so any mutable state on the Robot (motion history, calibration caches) doesn’t leak between tests.
- testing.pytest_plugin.scene(project_info: testing._project.ProjectInfo, robot_sim_config: testing.sim.SimRobotConfig) Callable[Ellipsis, None]¶
Factory that enters a
use_scenecontext for the current test.Call it once per test:
def test_foo(robot, scene, run_step): scene("empty_table.ftmap", start=(20, 50, 0)) run_step(my_step, robot)
The scene is detached automatically at the end of the test. Calling
scenetwice in one test replaces the previous scene.
- testing.pytest_plugin.run_step() Callable[Ellipsis, Any]¶
Sync wrapper that awaits
step.run_step(robot)with a timeout.Tests stay sync so this plugin doesn’t drag in pytest-asyncio. If you need multiple awaits sharing an event loop, write the test as
async defand use pytest-asyncio yourself —run_stepis the simple path for the common case.
- testing.pytest_plugin.pytest_sessionfinish(session: Any, exitstatus: int) None¶
Bypass interpreter shutdown when the mock HAL was exercised.
The pybind11-bound MockPlatform singleton has a destruction-order race with the motor/IMU wrapper destructors that can segfault at interpreter shutdown. The library’s own end-to-end tests work around this by running the mission in a subprocess that ``os._exit``s before any destructors run. The plugin does the same thing here, transparently.
Only fires when: - The
robotfixture was actually used (so we know the mock HALhas state to tear down).
All tests passed — on failure we want pytest’s normal exit path so CI gets an accurate error code and any debugger post-mortem runs.
The user hasn’t set
RACCOON_TESTING_NO_EXIT_SHORTCUT=1to debug.