Tools for test-writer
Running automated tests to confirm red/green
Test command:
mise exec -- godot --headless -s addons/gut/gut_cmdln.gd -gdir=res://tests/unit -gexit
Uses GUT v9.7.1, installed via gd-plug
(declared in plug.gd, addons/gut is gitignored like the project's other
addons). Options also live in .gutconfig.json at the repo root. Exit code
is 0 on all-pass, 1 on any failure — safe for a Red→Green loop.
On a fresh clone, or after plug.gd install/update touches addons/, run
godot --headless --import once first — otherwise GUT's class_names aren't
resolved yet and the run errors out.
A bare godot works only where mise's shims are on PATH; mise exec --
resolves it from mise.toml either way.
GUT will not tell you a test passed for the wrong reason
This is the failure mode that has actually cost this project time, repeatedly. A test passes when its assertions hold — not when they were meaningful:
- An assertion that iterates a collection is vacuously true when the collection is empty.
- A comparison between two outcomes holds trivially when both sides are untouched, because the thing under test never ran.
- An assertion that "nothing happened" is satisfied by any reason nothing happened, including an unrelated gate rejecting the operation first.
- Arithmetic that lands on a whole number cannot distinguish "rounded correctly" from "never rounded at all".
So: after a red→green transition, check what actually ran, not just the
totals line. Pick fixture values where the right answer, the wrong answer,
and the not-implemented answer are three different numbers, and assert
against the wrong ones too (assert_ne). When a test asserts a rejection,
make sure the mechanism under test is the only thing that could produce it.
Verifying editor/game behaviour that a headless test can't reach
Consider godot-ai before writing a manual-test document for
something it can actually drive (scene state, node properties, screenshots)
— if it can, a manual step may be the wrong call. That file has the criterion
for when it applies.
Linting the tests you write
gdlint has no hook behind it, so run it before you finish — see
docs/tools/gdtoolkit.md:
mise exec -- gdlint tests/
Where new test files belong
res://tests/ (top-level, non-recursive) is reserved for the Godot AI
addon's own McpTestSuite-based test_manage/test_run MCP tools — those
only work with a live editor + MCP connection, not headless/CI. Write new
GUT tests one level down, in res://tests/unit/, so the two test systems
don't collide.