一键导入
add-test
Use when writing tests for EmbodiChain modules, including observation functors, reward functors, solvers, sensors, environments, or any Python module
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Use when writing tests for EmbodiChain modules, including observation functors, reward functors, solvers, sensors, environments, or any Python module
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Use when adding a new simulation atomic action or motion primitive to EmbodiChain's AtomicActionEngine.
Use when a request asks to reference, refresh, write, or register project development context so the agent resolves the topic through agent_context/MAP.yaml and reads or updates the mapped Markdown context files.
Use when adding a new robot to EmbodiChain — scaffolds a RobotCfg subclass (single-file or package layout) with the _build_defaults hook, build_pk_serial_chain, registration, docs page, and test stub.
Claude adapter for the canonical EmbodiChain add-robot skill.
Claude adapter for the canonical EmbodiChain release skill.
Use when preparing, drafting, validating, or publishing an EmbodiChain release, including GitHub release notes, version tags, and release artifacts.
| name | add-test |
| description | Use when writing tests for EmbodiChain modules, including observation functors, reward functors, solvers, sensors, environments, or any Python module |
Write tests following EmbodiChain's conventions and patterns.
Tests mirror the source tree under tests/:
embodichain/lab/sim/solvers/pytorch_solver.py → tests/sim/solvers/test_pytorch_solver.py
embodichain/lab/gym/envs/managers/rewards.py → tests/gym/envs/managers/test_reward_functors.py
embodichain/toolkits/graspkit/pg_grasp/foo.py → tests/toolkits/test_pg_grasp.py
embodichain/lab/gym/envs/tasks/rl/push_cube.py → tests/gym/envs/tasks/test_push_cube.py
Rules:
test_<module>.pyembodichain/ structure under tests/__init__.py files in new tests/ subdirectories if neededUse when: testing functors, utility functions, pure math, config validation — anything that doesn't need a SimulationManager.
# ----------------------------------------------------------------------------
# Copyright (c) 2021-2026 DexForce Technology Co., Ltd.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# ...
# ----------------------------------------------------------------------------
from __future__ import annotations
import pytest
import torch
from embodichain.my_module import my_function
def test_expected_output():
result = my_function(input_value)
assert result == expected_value
def test_edge_case():
result = my_function(edge_input)
assert result is not None
Use when: tests need SimulationManager, GPU setup, or must run in a specific order. Share state via setup_method/teardown_method.
# ----------------------------------------------------------------------------
# Copyright (c) 2021-2026 DexForce Technology Co., Ltd.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# ...
# ----------------------------------------------------------------------------
from __future__ import annotations
import pytest
import torch
from embodichain.lab.sim import SimulationManager, SimulationManagerCfg
class TestMySimComponent:
def setup_method(self):
config = SimulationManagerCfg(headless=True, sim_device="cpu")
self.sim = SimulationManager(config)
# ... setup ...
def teardown_method(self):
self.sim.destroy()
SimulationManager.flush_cleanup_queue()
def test_basic_behavior(self):
result = self.sim.do_something()
assert result == expected_result
def test_raises_on_bad_input(self):
with pytest.raises(ValueError):
self.sim.do_something(bad_input)
Use the narrowest test type that proves the behavior:
tests/conftest.py automatically classifies conventional CUDA, renderer, and
real-simulation tests. Add @pytest.mark.gpu, @pytest.mark.slow, or
@pytest.mark.requires_sim explicitly only when the test's node id/source
cannot reveal that requirement (for example, a hidden CUDA helper or an
end-to-end toolkit test).GPU tests are skipped by default to keep normal test runs within the shared VRAM budget. Run them explicitly and serially:
# Default suite: GPU-marked tests are skipped.
pytest tests/
# Dedicated GPU suite. Do not add -n unless pytest-xdist is installed.
pytest tests/ --run-gpu -m gpu
For backend/device matrices, run the complete contract on one representative
configuration and use small (one environment, low-resolution) smoke tests for
the remaining configurations. Always destroy a real SimulationManager and
flush its cleanup queue in teardown.
Most functor tests don't need a live simulation. Use mock objects following the pattern in tests/gym/envs/managers/test_reward_functors.py:
from unittest.mock import MagicMock, Mock
class MockSim:
"""Mock simulation for functor tests."""
def __init__(self, num_envs: int = 4):
self.num_envs = num_envs
self.device = torch.device("cpu")
self._rigid_objects: dict = {}
def get_rigid_object(self, uid: str):
return self._rigid_objects.get(uid)
def add_rigid_object(self, obj):
self._rigid_objects[obj.uid] = obj
class MockEnv:
"""Mock environment for functor tests."""
def __init__(self, num_envs: int = 4):
self.num_envs = num_envs
self.device = torch.device("cpu")
self.sim = MockSim(num_envs)
Key points for mock objects:
num_envs and device attributes (functors use these)MagicMock(uid="...") for SceneEntityCfg parametersAsk the user:
Map the source path to test path:
embodichain/<subpath>/<module>.py → tests/<subpath>/test_<module>.py
Check if the test file already exists — append new test classes/functions if so.
digraph test_style {
rankdir=LR;
"Needs SimulationManager?" -> "Class style" [label="yes"];
"Needs SimulationManager?" -> "pytest style" [label="no"];
"Tests share state/order?" -> "Class style" [label="yes"];
"Tests share state/order?" -> "pytest style" [label="no"];
}
Use the appropriate template (pytest or class style above).
Rules:
from __future__ import annotations — after header, before importstest_<scenario> (descriptive, not just test_foo)if __name__ == "__main__" BlockInclude this for tests that support optional visual/interactive debugging:
if __name__ == "__main__":
# For visual debugging: set is_visual=True when calling env methods
test_obj = TestMyComponent()
test_obj.setup_method()
# ... manually run test logic ...
# Single file
pytest tests/<subpath>/test_<module>.py -v
# Single test function
pytest tests/<subpath>/test_<module>.py::test_expected_output -v
# GPU-specific test
pytest tests/<subpath>/test_<module>.py --run-gpu -m gpu -v
# Single test class method
pytest tests/<subpath>/test_<module>.py::TestMyClass::test_basic_behavior -v
blackblack tests/<subpath>/test_<module>.py
| Convention | Rule |
|---|---|
| File header | Apache 2.0 copyright block (same 15 lines as source) |
| File naming | test_<module>.py |
| Function naming | test_<scenario> |
from __future__ | Required after header |
| Magic numbers | Define as named constants with explanatory comments |
| Simulation tests | Initialize/teardown in setup_method/teardown_method |
| CUDA coverage | Use @pytest.mark.gpu; run with --run-gpu -m gpu |
| Long integration | Use @pytest.mark.slow; keep it out of normal PR runs |
| Pure-logic tests | Use mock objects, no real sim |
SceneEntityCfg | Use MagicMock(uid="...") in tests |
| Assertions | assert, pytest.approx, torch.allclose, pytest.raises |
| Entry block | if __name__ == "__main__" for visual debugging support |
| Mistake | Fix |
|---|---|
| Missing Apache header on test file | Copy the 15-line copyright block |
Using real SimulationManager for functor tests | Use MockEnv/MockSim — much faster, no GPU needed |
| Hardcoded numbers without explanation | Define as EXPECTED_DISTANCE = 0.5 # cube at origin, target at (0.5, 0, 0) |
| Testing multiple concepts in one function | Split into separate test_<scenario> functions |
| Forgetting cleanup | Call self.sim.destroy() and SimulationManager.flush_cleanup_queue() in teardown |
| Using full matrices | Use one full representative case and low-resource smoke coverage elsewhere |
Not running black on test file | CI checks all files including tests |
| Action | Command |
|---|---|
| Run default tests | pytest tests/ |
| Run GPU tests | pytest tests/ --run-gpu -m gpu |
| Run single file | pytest tests/<path>/test_<name>.py -v |
| Run single test | pytest tests/<path>::test_<name> -v |
| Run with print output | pytest -s tests/<path>/test_<name>.py |
| Format | black tests/<path>/test_<name>.py |