CLI Reference
Every gdtest flag, env var, and subcommand.
Synopsis
gdtest # scan the project using discovery globs
gdtest <target>... [options]
gdtest res://test/foo.gd::test_bar # one test, no worker pool
gdtest init [--no-editor] [--force]
gdtest aggregate <shard.xml>... [--output combined.xml]
gdtest migrate gut|gdunit4 <inputs>... [--out DIR]A <target> is one of:
path/to/file.gd— run everytest_*in the filepath/to/dir— walk the directory using discovery globsres://path/to/file.gd— same, with project-relative prefixfile.gd::test_bar— run exactly that one test function (::separates the file path from the function name; no worker pool is created, so you get full stderr output directly)
Discovery globs (configurable via the include and exclude settings):
test/**/*.gd— any.gdfile inside atest/directory**/*.test.gd— co-located test files anywhere in the project
When walking a directory, gdtest skips hidden folders (.godot, .git…),
addons, folders with a .gdignore, and nested Godot projects, as the Godot
editor does: an addon's own tests never run as the project's. A directory or
file you name directly is always used.
Options
Most options can be set three ways: as a CLI flag, an environment variable, or a configuration key. A flag wins over the env var, which wins over the config file.
Running
| Flag | Env var | Default | Description |
|---|---|---|---|
-j, --jobs <N> | GDTEST_JOBS | CPU count | Parallel worker count (clamped by test count) |
--isolation <MODE> | GDTEST_ISOLATION | file | file | test (see below) |
--timeout <MS> | GDTEST_TIMEOUT | 5000 | Per-test timeout; a test that exceeds it is an error and its worker restarts |
--timeout-warn <MS> | GDTEST_TIMEOUT_WARN | off | Warn about slow tests without stopping them; must be below --timeout |
--fail-fast | GDTEST_FAIL_FAST | off | Stop after the first failure or error |
--retries <N> | GDTEST_RETRIES | 0 | Re-run a failing test up to N more times; timeouts and crashes are not retried |
--profile <NAME> | — | — | Activate a [profile.NAME] block from the config |
--watch | — | off | Re-run the targets after every .gd change; Ctrl-C to exit |
--no-rewrite | — | off | Run assert(a == b) as written instead of rewriting it for rich diffs |
--update-snapshots | — | off | Accept new or changed snapshot values |
--seed <N> | GDTEST_SEED | random | Fix the RNG seed of forall property tests |
--bench | — | off | Run only bench_* functions (see Running Tests) |
Selecting tests
| Flag | Env var | Description |
|---|---|---|
--filter <REGEX> | — | Only tests whose file :: func matches the regex |
--tag <TAG> | GDTEST_INCLUDE_TAGS | Only tests with this tag (repeatable, any of them) |
--exclude-tag <TAG> | GDTEST_EXCLUDE_TAGS | Skip tests with this tag (repeatable) |
--changed-only | — | Only tests affected by uncommitted changes (git diff HEAD) |
--changed-since <REF> | — | Only tests affected by changes since a git ref, e.g. origin/main |
--partition <SPEC> | — | Run one shard of the suite (see below) |
--list | — | Print the discovered tests as file :: func and exit |
Output
| Flag | Env var | Default | Description |
|---|---|---|---|
--reporter <KIND> | GDTEST_REPORTER | pretty | pretty | tap | json | junit |
--output-dir <DIR> | — | — | Write JSON events as numbered files under DIR (used by the editor panel) |
--html-report [PATH] | — | gdtest-report.html | Write a standalone HTML report after the run |
--coverage | — | off | Instrument sources and write coverage/lcov.info |
--min-coverage <PCT> | — | — | Fail when total line coverage is below PCT; needs --coverage |
--coverage-exclude <GLOB> | GDTEST_COVERAGE_EXCLUDE | — | Leave matching files out of coverage (repeatable) |
--mutate <FILE> | — | — | Mutation testing of one source file |
Godot
| Flag | Env var | Default | Description |
|---|---|---|---|
--godot-exe <PATH> | GODOT_EXE | auto-discovered | Godot 4 binary |
--display-mode <MODE> | GDTEST_DISPLAY_MODE | headless | headless | windowed |
--project-path <DIR> | — | . | Godot project root |
--harness <PATH> | GDTEST_HARNESS | addons/gdtest/gdtest_worker.gd | Worker script |
--no-auto-import | — | off | Skip the one-time godot --headless --import that runs when the class cache is missing |
Reporters
pretty (default) — coloured human-readable output with a spinner and summary line.
tap — TAP v14; works with tap-junit, tap-parser and most CI TAP consumers.
json — one JSON event per line, for tools that read results as they arrive.
junit — JUnit XML on stdout. Redirect it to a file for GitHub Actions or GitLab CI test reports.
gdtest test/ --reporter junit > results.xmlIsolation modes
file (default) — a worker stays alive across the tests of a file, and
across files. Fast; tests that run in the same worker share autoload state.
test — the worker restarts between every test. About 200 ms more per
test, but each test starts with clean autoloads and Engine metadata. Use it
when tests change global singletons and those changes leak.
Instead of switching the whole run, mark only the files or tests that need it:
## @isolation test
extends GdTest # every test in this file gets its own worker
## @isolation file
func test_fast_path() -> void: # except this one
passPartitioning (CI sharding)
Split the suite across CI jobs with --partition, then merge the JUnit files:
# Round-robin: each job gets every 3rd test
gdtest test/ --partition count:1/3 --reporter junit > shard-1.xml
gdtest test/ --partition count:2/3 --reporter junit > shard-2.xml
gdtest test/ --partition count:3/3 --reporter junit > shard-3.xml
# Hash-based: the same test always lands on the same shard
gdtest test/ --partition hash:1/3
# After all shards
gdtest aggregate shard-*.xml --output combined.xmlcount:N/M takes every M-th test starting at position N−1.
hash:N/M uses an FNV-1a hash of script::func, so a test keeps its shard as
the suite grows.
Subcommands
gdtest init
gdtest init
gdtest init --no-editor
gdtest init --project-path /path/to/game
gdtest init --forceInstalls the bundled addons/gdtest/ runtime and the addons/gdtest_editor/
panel into the project. --no-editor installs only the runtime.
If a file already exists with different contents, init stops rather than
overwrite local changes. --force replaces the project copy with the version
bundled in the current gdtest binary.
gdtest aggregate
gdtest aggregate shard-1.xml shard-2.xml --output combined.xmlMerges JUnit XML files written by --reporter junit into one report, on stdout
unless --output is given.
gdtest migrate
gdtest migrate gut test/
gdtest migrate gdunit4 test/ --out .gdtest_rewrite/gdunit4Writes gdtest versions of GUT or gdUnit4 tests next to the originals, which are
left untouched, plus a report of what could not be converted. Output goes to
.gdtest_rewrite/<framework> unless --out is given. See
Migrating from GUT and
Migrating from gdUnit4.
Single-test mode
gdtest res://test/test_player.gd::test_jump # bypasses the pool; full stderr visible