Godot GoDotTest
Use this skill when a Godot 4.6 + .NET/C# project uses Chickensoft GoDotTest for in-engine testing.
GoDotTest is a C#-first test runner that executes inside the Godot process. It is not xUnit, NUnit, or MSTest. Tests extend TestClass, use GoDotTest-specific lifecycle attributes, run sequentially inside the scene tree, and are invoked via Godot command-line arguments. Getting this wrong produces tests that compile but silently never execute, or that crash because of wrong scene wiring.
Prefer this skill whenever the task involves writing, scaffolding, running, debugging, or collecting coverage for GoDotTest-based test suites.
Purpose
This skill is used to:
- write correct GoDotTest test classes with proper lifecycle attributes
- set up the test scene and main-scene redirection for running tests
- produce correct CLI commands for running tests, filtering suites, and collecting coverage
- generate VSCode launch/task configurations for debugging tests
- advise on assertion and mocking library choices compatible with GoDotTest
- guide
GodotTestDriver usage for integration or UI-style GoDotTest suites
- separate what belongs in GoDotTest (runtime-dependent) from what can stay in pure .NET tests
- scaffold new test suites using the companion template
Use this skill when
Invoke this skill for tasks such as:
- adding a new GoDotTest test class or test suite
- setting up GoDotTest in a project for the first time
- writing tests that need the scene tree, node references, signals, or engine timing
- configuring VSCode or Visual Studio to debug GoDotTest runs
- running tests from the command line or CI/CD
- collecting code coverage via coverlet for GoDotTest runs
- deciding which tests belong in GoDotTest vs. pure .NET test projects
- troubleshooting tests that do not appear, do not run, or crash on startup
Trigger examples
- "Add a GoDotTest suite for this node"
- "Set up GoDotTest in my Godot project"
- "How do I debug GoDotTest tests in VSCode?"
- "Run only one test suite from the command line"
- "Collect coverage for my Godot C# tests"
- "My GoDotTest tests are not running"
Do not use this skill when
Do not use this skill when:
- the test can run as a pure .NET test with no Godot runtime dependency — use a standard test framework instead
- the user wants a test strategy review rather than implementation — use
test-strategy-review
- the user wants to review scene architecture rather than test it — use
scene-architecture-review
- the task is about xUnit, NUnit, MSTest, or other non-GoDotTest frameworks
- the user only needs assertion library recommendations without writing GoDotTest suites
Pattern
- Primary pattern: Tool Wrapper
- Secondary pattern: Generator
Why: the skill mainly packages GoDotTest conventions, lifecycle rules, setup patterns, CLI flags, and debugging/coverage guidance. The Generator secondary produces test suite scaffolds.
Companion files
references/godotest-quick-ref.md — distilled API reference: attributes, lifecycle order, CLI flags, project setup, coverage commands, and common pitfalls.
assets/test-suite-scaffold.md — fill-in template for a new GoDotTest test class.
assets/driver-scaffold.md — reusable template for custom GodotTestDriver drivers and GoDotTest integration-style test usage.
Inputs
Collect or infer these inputs when available:
| Input |
Required |
Description |
| What to test |
Yes |
The node, system, signal flow, or behavior under test |
| Project structure |
Recommended |
Whether tests live in the same project or a separate test project |
| Existing test scene |
Recommended |
Whether a test scene and main-scene redirect are already wired |
| Godot version |
Recommended |
Godot 4.x version (affects API surface) |
| GoDotTest version |
Recommended |
NuGet package version (latest is 2.0.x) |
| Assertion/mock library |
Optional |
Whether the project uses Shouldly, FluentAssertions, LightMock, LightMoq, GodotTestDriver, or others |
| Integration/UI coverage |
Optional |
Whether the suite needs fixtures, input simulation, node drivers, or wait helpers |
| Coverage requirement |
Optional |
Whether coverlet integration is needed |
| CI/CD target |
Optional |
Whether tests run headless in CI |
If the project has no GoDotTest setup yet, guide the full first-time setup before writing tests.
Workflow
1. Confirm GoDotTest is installed and wired
Check for:
Chickensoft.GoDotTest NuGet reference in the .csproj
- a test scene (e.g.
test/Tests.tscn) with a root node script that calls GoTest.RunTests
- main-scene redirection that checks
TestEnvironment.From(OS.GetCmdlineArgs()) and branches into test mode when --run-tests is present
If any piece is missing, guide its creation before writing test classes. See references/godotest-quick-ref.md § Project setup.
2. Write or scaffold the test class
Use assets/test-suite-scaffold.md as the starting point.
Rules:
- extend
TestClass
- accept
Node testScene in the constructor and pass it to base(testScene)
- use GoDotTest attributes only:
[Test], [Setup], [Cleanup], [SetupAll], [CleanupAll], [Failure]
- do not use xUnit, NUnit, or MSTest attributes — they are ignored by GoDotTest
- tests run in declaration order, not alphabetically
- tests run sequentially — no parallelism
async Task tests are awaited; synchronous tests return void
- add nodes to the scene tree via
testScene.AddChild(node) and clean them up in [Cleanup] or [CleanupAll]
- nodes that never enter the scene tree must be freed with
Free(), not QueueFree()
3. Choose assertion, mocking, and integration tools
GoDotTest is a test runner only — it has no built-in assertions or mocks.
Recommended stack:
| Need |
Recommended |
Notes |
| Assertions |
Shouldly or FluentAssertions |
Any .NET assertion library works |
| Mocking |
LightMock.Generator + LightMoq |
Compile-time mock generation, safe in Godot runtime |
| Integration / UI |
GodotTestDriver |
Adds fixtures, node drivers, input simulation, and wait helpers for Godot runtime tests |
Do not recommend Moq — it uses runtime IL emit which can fail in Godot's .NET host.
If the suite is an integration or UI flow test and the project uses GodotTestDriver, guide these specifics explicitly:
- add a
Chickensoft.GodotTestDriver package reference together with using Chickensoft.GodotTestDriver;, using Chickensoft.GodotTestDriver.Drivers;, and using Chickensoft.GodotTestDriver.Util; when wait extensions such as WithinSeconds are used
- remember
GodotTestDriver is not a test executor — GoDotTest still owns suite discovery and execution
- use
Fixture to create, load, add, and clean up scenes or nodes safely on the main thread
- call
await fixture.Cleanup() in a finally block or equivalent guaranteed cleanup path when the test allocates runtime objects
- prefer built-in drivers like
ButtonDriver, LabelDriver, ControlDriver, or compose custom drivers around producer lambdas
- producer functions should return
null when a node is absent instead of throwing
- after simulated input, use wait helpers such as
WithinSeconds or DuringSeconds when state changes require more frames to process
See references/godotest-quick-ref.md for a ready-to-adapt GodotTestDriver example and validation checklist.
4. Configure run and debug
Provide or verify:
- CLI:
$GODOT --run-tests --quit-on-finish to run all suites
- CLI filter:
$GODOT --run-tests=SuiteName --quit-on-finish for one suite; --run-tests=SuiteName.MethodName for one method
- VSCode launch.json:
Debug Tests and Debug Current Test configurations (see quick ref)
- Visual Studio:
launchSettings.json in the test project Properties/ folder
- Stop on error:
--stop-on-error to halt at first failure
- Sequential skip:
--sequential to skip remaining methods after a failure within a suite
5. Collect coverage (when needed)
Guide coverlet setup:
coverlet \
"./.godot/mono/temp/bin/Debug" --verbosity detailed \
--target $GODOT \
--targetargs "--run-tests --coverage --quit-on-finish" \
--format "opencover" \
--output "./coverage/coverage.xml" \
--exclude-by-file "**/test/**/*.cs" \
--exclude-by-file "**/*Microsoft.NET.Test.Sdk.Program.cs" \
--exclude-by-file "**/Godot.SourceGenerators/**/*.cs" \
--exclude-assemblies-without-sources "missingall"
Key: the --coverage flag tells GoDotTest to force-exit the process so coverlet can capture data correctly. A few harmless error messages appear on exit — disregard them.
6. Exclude tests from release builds
Ensure the .csproj excludes test files from ExportRelease:
<PropertyGroup>
<DefaultItemExcludes Condition="'$(Configuration)' == 'ExportRelease'">
$(DefaultItemExcludes);test/**/*
</DefaultItemExcludes>
</PropertyGroup>
Adjust the glob if tests live in a different folder.
7. Validate
- Build succeeds with
dotnet build --no-restore
- Tests appear in GoDotTest output when launched with
--run-tests
- Specific suite filtering works with
--run-tests=SuiteName
[Setup]/[Cleanup] run in the expected order around each test
- Nodes added to the tree in tests are cleaned up
- Coverage report generates without empty results (if coverlet is used)
If the suite uses GodotTestDriver, also validate that:
Chickensoft.GodotTestDriver is referenced and the needed namespaces resolve (Chickensoft.GoDotTest, Chickensoft.GodotTestDriver, Chickensoft.GodotTestDriver.Drivers, Chickensoft.GodotTestDriver.Util)
Fixture cleanup always runs, even when assertions fail
- driver actions fail with actionable exceptions such as
InvalidOperationException, not NullReferenceException
- simulated input plus
WithinSeconds / DuringSeconds produces the expected state transition
- any custom cleanup steps added through the fixture actually execute
Output contract
When this skill generates a test class, the output must include:
- the complete C# test class file
- any required scene or project setup steps that are missing
- the CLI command to run the new tests
- notes on which assertions/mocks are used and why
- fixture or driver setup notes when the suite uses
GodotTestDriver
When this skill guides first-time setup, the output must include:
- NuGet package reference to add
- test scene script
- main-scene redirect (if the project is a game, not a package)
.csproj exclude for release builds
- VSCode launch/task configurations
Common pitfalls
- Using xUnit/NUnit attributes alongside GoDotTest — they are silently ignored.
- Forgetting to wire the test scene or main-scene redirect — tests compile but never execute.
- Using
QueueFree() on nodes that were never added to the tree — they leak because QueueFree requires deferred scene-tree processing.
- Expecting parallel test execution — GoDotTest is intentionally sequential to avoid race conditions in engine state.
- Missing
--coverage flag when running with coverlet — coverage capture fails silently.
- Using
Moq instead of LightMock.Generator — runtime IL emit can fail in Godot's .NET host.
- Test class name not matching the file name —
--run-tests=FileName filter breaks.
- Forgetting
await on async test methods — test appears to pass instantly without actually running the async body.
- Not increasing Godot network limits for logging — test output may be truncated.
- Treating
GodotTestDriver as the test runner — it only helps drive integration tests; GoDotTest still executes the suite.
- Clicking or typing with
GodotTestDriver and then asserting immediately when more frames are needed — use waiting helpers when behavior is asynchronous.
- Writing producer lambdas that throw when the node is missing — drivers should handle absent nodes gracefully until used.
1---2name: godot-godottest3description: Use when a Godot/.NET task needs a Layer 4 overlay skill for GoDotTest-based C# testing, and the agent must write, run, debug, or collect coverage for suites, scene wiring, CLI invocation, VS Code debug configs, or coverage commands instead of guessing xUnit/NUnit patterns that do not apply inside Godot runtime.4---56# Godot GoDotTest78Use this skill when a Godot 4.6 + .NET/C# project uses **Chickensoft GoDotTest** for in-engine testing.910GoDotTest is a C#-first test runner that executes inside the Godot process. It is **not** xUnit, NUnit, or MSTest. Tests extend `TestClass`, use GoDotTest-specific lifecycle attributes, run sequentially inside the scene tree, and are invoked via Godot command-line arguments. Getting this wrong produces tests that compile but silently never execute, or that crash because of wrong scene wiring.1112Prefer this skill whenever the task involves writing, scaffolding, running, debugging, or collecting coverage for GoDotTest-based test suites.1314## Purpose1516This skill is used to:1718- write correct GoDotTest test classes with proper lifecycle attributes19- set up the test scene and main-scene redirection for running tests20- produce correct CLI commands for running tests, filtering suites, and collecting coverage21- generate VSCode launch/task configurations for debugging tests22- advise on assertion and mocking library choices compatible with GoDotTest23- guide `GodotTestDriver` usage for integration or UI-style GoDotTest suites24- separate what belongs in GoDotTest (runtime-dependent) from what can stay in pure .NET tests25- scaffold new test suites using the companion template2627## Use this skill when2829Invoke this skill for tasks such as:3031- adding a new GoDotTest test class or test suite32- setting up GoDotTest in a project for the first time33- writing tests that need the scene tree, node references, signals, or engine timing34- configuring VSCode or Visual Studio to debug GoDotTest runs35- running tests from the command line or CI/CD36- collecting code coverage via coverlet for GoDotTest runs37- deciding which tests belong in GoDotTest vs. pure .NET test projects38- troubleshooting tests that do not appear, do not run, or crash on startup3940### Trigger examples4142- "Add a GoDotTest suite for this node"43- "Set up GoDotTest in my Godot project"44- "How do I debug GoDotTest tests in VSCode?"45- "Run only one test suite from the command line"46- "Collect coverage for my Godot C# tests"47- "My GoDotTest tests are not running"4849## Do not use this skill when5051Do not use this skill when:5253- the test can run as a pure .NET test with no Godot runtime dependency — use a standard test framework instead54- the user wants a test **strategy review** rather than implementation — use `test-strategy-review`55- the user wants to review scene architecture rather than test it — use `scene-architecture-review`56- the task is about xUnit, NUnit, MSTest, or other non-GoDotTest frameworks57- the user only needs assertion library recommendations without writing GoDotTest suites5859## Pattern6061- Primary pattern: **Tool Wrapper**62- Secondary pattern: **Generator**6364Why: the skill mainly packages GoDotTest conventions, lifecycle rules, setup patterns, CLI flags, and debugging/coverage guidance. The Generator secondary produces test suite scaffolds.6566## Companion files6768- `references/godotest-quick-ref.md` — distilled API reference: attributes, lifecycle order, CLI flags, project setup, coverage commands, and common pitfalls.69- `assets/test-suite-scaffold.md` — fill-in template for a new GoDotTest test class.70- `assets/driver-scaffold.md` — reusable template for custom `GodotTestDriver` drivers and GoDotTest integration-style test usage.7172## Inputs7374Collect or infer these inputs when available:7576| Input | Required | Description |77|---|---|---|78| What to test | Yes | The node, system, signal flow, or behavior under test |79| Project structure | Recommended | Whether tests live in the same project or a separate test project |80| Existing test scene | Recommended | Whether a test scene and main-scene redirect are already wired |81| Godot version | Recommended | Godot 4.x version (affects API surface) |82| GoDotTest version | Recommended | NuGet package version (latest is 2.0.x) |83| Assertion/mock library | Optional | Whether the project uses Shouldly, FluentAssertions, LightMock, LightMoq, GodotTestDriver, or others |84| Integration/UI coverage | Optional | Whether the suite needs fixtures, input simulation, node drivers, or wait helpers |85| Coverage requirement | Optional | Whether coverlet integration is needed |86| CI/CD target | Optional | Whether tests run headless in CI |8788If the project has no GoDotTest setup yet, guide the full first-time setup before writing tests.8990## Workflow9192### 1. Confirm GoDotTest is installed and wired9394Check for:9596- `Chickensoft.GoDotTest` NuGet reference in the `.csproj`97- a test scene (e.g. `test/Tests.tscn`) with a root node script that calls `GoTest.RunTests`98- main-scene redirection that checks `TestEnvironment.From(OS.GetCmdlineArgs())` and branches into test mode when `--run-tests` is present99100If any piece is missing, guide its creation before writing test classes. See `references/godotest-quick-ref.md` § Project setup.101102### 2. Write or scaffold the test class103104Use `assets/test-suite-scaffold.md` as the starting point.105106Rules:107108- extend `TestClass`109- accept `Node testScene` in the constructor and pass it to `base(testScene)`110- use GoDotTest attributes only: `[Test]`, `[Setup]`, `[Cleanup]`, `[SetupAll]`, `[CleanupAll]`, `[Failure]`111- do **not** use xUnit, NUnit, or MSTest attributes — they are ignored by GoDotTest112- tests run **in declaration order**, not alphabetically113- tests run **sequentially** — no parallelism114- `async Task` tests are awaited; synchronous tests return `void`115- add nodes to the scene tree via `testScene.AddChild(node)` and clean them up in `[Cleanup]` or `[CleanupAll]`116- nodes that never enter the scene tree must be freed with `Free()`, not `QueueFree()`117118### 3. Choose assertion, mocking, and integration tools119120GoDotTest is a **test runner only** — it has no built-in assertions or mocks.121122Recommended stack:123124| Need | Recommended | Notes |125|---|---|---|126| Assertions | `Shouldly` or `FluentAssertions` | Any .NET assertion library works |127| Mocking | `LightMock.Generator` + `LightMoq` | Compile-time mock generation, safe in Godot runtime |128| Integration / UI | `GodotTestDriver` | Adds fixtures, node drivers, input simulation, and wait helpers for Godot runtime tests |129130Do not recommend `Moq` — it uses runtime IL emit which can fail in Godot's .NET host.131132If the suite is an integration or UI flow test and the project uses `GodotTestDriver`, guide these specifics explicitly:133134- add a `Chickensoft.GodotTestDriver` package reference together with `using Chickensoft.GodotTestDriver;`, `using Chickensoft.GodotTestDriver.Drivers;`, and `using Chickensoft.GodotTestDriver.Util;` when wait extensions such as `WithinSeconds` are used135- remember `GodotTestDriver` is **not** a test executor — `GoDotTest` still owns suite discovery and execution136- use `Fixture` to create, load, add, and clean up scenes or nodes safely on the main thread137- call `await fixture.Cleanup()` in a `finally` block or equivalent guaranteed cleanup path when the test allocates runtime objects138- prefer built-in drivers like `ButtonDriver`, `LabelDriver`, `ControlDriver`, or compose custom drivers around producer lambdas139- producer functions should return `null` when a node is absent instead of throwing140- after simulated input, use wait helpers such as `WithinSeconds` or `DuringSeconds` when state changes require more frames to process141142See `references/godotest-quick-ref.md` for a ready-to-adapt `GodotTestDriver` example and validation checklist.143144### 4. Configure run and debug145146Provide or verify:147148- **CLI**: `$GODOT --run-tests --quit-on-finish` to run all suites149- **CLI filter**: `$GODOT --run-tests=SuiteName --quit-on-finish` for one suite; `--run-tests=SuiteName.MethodName` for one method150- **VSCode launch.json**: `Debug Tests` and `Debug Current Test` configurations (see quick ref)151- **Visual Studio**: `launchSettings.json` in the test project `Properties/` folder152- **Stop on error**: `--stop-on-error` to halt at first failure153- **Sequential skip**: `--sequential` to skip remaining methods after a failure within a suite154155### 5. Collect coverage (when needed)156157Guide coverlet setup:158159```bash160coverlet \161 "./.godot/mono/temp/bin/Debug" --verbosity detailed \162 --target $GODOT \163 --targetargs "--run-tests --coverage --quit-on-finish" \164 --format "opencover" \165 --output "./coverage/coverage.xml" \166 --exclude-by-file "**/test/**/*.cs" \167 --exclude-by-file "**/*Microsoft.NET.Test.Sdk.Program.cs" \168 --exclude-by-file "**/Godot.SourceGenerators/**/*.cs" \169 --exclude-assemblies-without-sources "missingall"170```171172Key: the `--coverage` flag tells GoDotTest to force-exit the process so coverlet can capture data correctly. A few harmless error messages appear on exit — disregard them.173174### 6. Exclude tests from release builds175176Ensure the `.csproj` excludes test files from `ExportRelease`:177178```xml179<PropertyGroup>180 <DefaultItemExcludes Condition="'$(Configuration)' == 'ExportRelease'">181 $(DefaultItemExcludes);test/**/*182 </DefaultItemExcludes>183</PropertyGroup>184```185186Adjust the glob if tests live in a different folder.187188### 7. Validate189190- Build succeeds with `dotnet build --no-restore`191- Tests appear in GoDotTest output when launched with `--run-tests`192- Specific suite filtering works with `--run-tests=SuiteName`193- `[Setup]`/`[Cleanup]` run in the expected order around each test194- Nodes added to the tree in tests are cleaned up195- Coverage report generates without empty results (if coverlet is used)196197If the suite uses `GodotTestDriver`, also validate that:198199- `Chickensoft.GodotTestDriver` is referenced and the needed namespaces resolve (`Chickensoft.GoDotTest`, `Chickensoft.GodotTestDriver`, `Chickensoft.GodotTestDriver.Drivers`, `Chickensoft.GodotTestDriver.Util`)200- `Fixture` cleanup always runs, even when assertions fail201- driver actions fail with actionable exceptions such as `InvalidOperationException`, not `NullReferenceException`202- simulated input plus `WithinSeconds` / `DuringSeconds` produces the expected state transition203- any custom cleanup steps added through the fixture actually execute204205## Output contract206207When this skill generates a test class, the output must include:2082091. the complete C# test class file2102. any required scene or project setup steps that are missing2113. the CLI command to run the new tests2124. notes on which assertions/mocks are used and why2135. fixture or driver setup notes when the suite uses `GodotTestDriver`214215When this skill guides first-time setup, the output must include:2162171. NuGet package reference to add2182. test scene script2193. main-scene redirect (if the project is a game, not a package)2204. `.csproj` exclude for release builds2215. VSCode launch/task configurations222223## Common pitfalls224225- Using xUnit/NUnit attributes alongside GoDotTest — they are silently ignored.226- Forgetting to wire the test scene or main-scene redirect — tests compile but never execute.227- Using `QueueFree()` on nodes that were never added to the tree — they leak because `QueueFree` requires deferred scene-tree processing.228- Expecting parallel test execution — GoDotTest is intentionally sequential to avoid race conditions in engine state.229- Missing `--coverage` flag when running with coverlet — coverage capture fails silently.230- Using `Moq` instead of `LightMock.Generator` — runtime IL emit can fail in Godot's .NET host.231- Test class name not matching the file name — `--run-tests=FileName` filter breaks.232- Forgetting `await` on async test methods — test appears to pass instantly without actually running the async body.233- Not increasing Godot network limits for logging — test output may be truncated.234- Treating `GodotTestDriver` as the test runner — it only helps drive integration tests; `GoDotTest` still executes the suite.235- Clicking or typing with `GodotTestDriver` and then asserting immediately when more frames are needed — use waiting helpers when behavior is asynchronous.236- Writing producer lambdas that throw when the node is missing — drivers should handle absent nodes gracefully until used.