Run & Write CPU Tests
docs/contributing/testing_guide.md is authoritative for the layer hierarchy, the
*_on_cpu.py naming rule, placement, coverage, the local pytest invocations, and
the steps for adding a test. Follow it. This skill adds what it does not cover.
What CI does that the guide's local commands don't
- The CPU job exports
TORCH_COMPILE_DISABLE=1andTORCHINDUCTOR_DISABLE=1(.github/workflows/cpu_unit_tests.yml). Set both locally when reproducing a failure that only CI sees. - On pull requests the job triggers on
types: [labeled]and only when the label isci— a green checks page on an unlabelled PR means the tests never ran. The label is single-use:drop-ci-labels.ymlremoves it on everysynchronize, so a new push does not re-run the job until you re-addci. tests/special_sanity/runs as its own job; those files aretest_*.py, so the CPU job'spython_filesoverride deliberately skips them.
Idioms the guide leaves to the reader
Configs — construct normally:
cfg = DiffusionLossConfig(loss_mode="flow_dppo")
Bypass __init__ only when __post_init__ does I/O (loading tokenizers, resolving
paths), as DiffusionModelConfig does:
cfg = object.__new__(DiffusionModelConfig)
object.__setattr__(cfg, "architecture", "QwenImagePipeline")
object.__setattr__(cfg, "algorithm", "dpo")
object.__setattr__ is needed because BaseConfig gates assignment through
_mutable_fields, not because the dataclass is frozen
(config.md). Reaching for this where plain construction
works is a review comment.
Mocks and assertions — MagicMock the transformer and assert on call args and
output shapes rather than on real model output. TensorDict batches usually carry
metadata, not pixels (TensorDict({}, batch_size=2) plus the fields under test).
Use torch.testing.assert_close(a, b, rtol=..., atol=...) for tensors and
pytest.approx for scalars — never .equal() on floats.
Before opening a PR
Paste the command and its output into the PR body (mandatory —
commit-and-pr), then run pre-commit run --all-files.