godot-test-writing
Creates focused regression tests for Godot 4.6 C# using standardized layers like headless sessions and service tests.
Install
mkdir -p .claude/skills/godot-test-writing && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/18319" && unzip -o skill.zip -d .claude/skills/godot-test-writing && rm skill.zipInstalls to .claude/skills/godot-test-writing
Activation
This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.
Write and revise focused regression tests for this Godot 4.6 C# repository. Use when Codex needs to add, update, or evaluate tests under `tests/`, choose between service/runtime/headless/text/snapshot coverage, decide what assertions belong in a test, reuse project shared test fixtures, or verify that a change has appropriate Godot headless regression coverage.Key capabilities
- →Write focused regression tests for Godot 4.6 C#
- →Choose appropriate test layers (service, runtime, headless)
- →Reuse project shared test fixtures
- →Assert stable contracts and failure modes
- →Validate tests using Godot headless commands
How it works
The skill loads context from design documents and existing tests, chooses the narrowest appropriate test layer, reuses shared project fixtures, writes the test runner, and asserts stable contracts and failure modes.
Inputs & outputs
When to use godot-test-writing
- →Write regression tests for game logic
- →Add headless session test coverage
- →Validate runtime state after changes
About this skill
Godot Test Writing
Use this skill to add narrow, maintainable regressions that protect runtime contracts without turning tests into implementation mirrors.
Load Context
- Read
docs/design/project_context_units.mdfirst. - Map the requested change to the owning context unit and always include CU-19. Include CU-21 when the test drives
HeadlessGameTestSession,GameTextCommandRunner, text snapshots, or command scripts. - Read existing tests in the nearest
tests/<domain>/folder before writing a new runner. Usergorfindto discover actual filenames; do not guess test paths. - Read the owner code and nearby helpers that the existing tests use. Prefer matching local patterns over introducing a new test style.
Choose Test Layer
Choose the narrowest layer that proves the behavior:
- Pure service/rule test: Instantiate the service, DTO, validator, or rules class directly when the bug is local and does not require scene or session state.
- Runtime/facade test: Use
GameRuntimeFacade,WorldMapRuntimeProxy, or owner modules when the behavior is a cross-system command, modal, reward, warehouse, battle, or world transition. - Headless session test: Use
HeadlessGameTestSessionwhen the behavior requiresGameSession + GameRuntimeFacadelifecycle, save locks, content catalog setup, or world loading without UI. - Text command/snapshot test: Use
GameTextCommandRunnerfor automation-facing command behavior and snapshot fields. Followtests/text_runtime/README.md. - Scene/UI schema test: Test scene-facing payload shape, signal/callable contracts, and stable UI data. Do not use UI tests for rule logic that belongs in services.
- Application E2E test: Use
tests/e2e/only when the contract requires the configured production main scene, canonical autoloads, real Godot input propagation, scene transitions, or a cold-process save/load journey. Drive UI throughE2eInputDriver, isolateuser://throughtests/run_e2e_suite.py, and keep multi-process steps serialized in one declared sandbox group. A deterministic E2E seed may fix randomness, but must not invoke callbacks/runtime commands directly or force an outcome. - Battle simulation or balance test: Do not include routine numeric simulation, balance, benchmark, or analysis runners unless the user explicitly asks for simulation or balance work. Use
battle-sim-analysisfor that workflow.
Reuse Shared Framework
Prefer existing project fixtures:
- Use
tests/shared/TestHarness.csfor assertions and final status. Avoid ad hocGD.PushErrorassertion frameworks in new tests. - Use
TestHarness.Finish(...)as the only normal runner-level finalizer drain. Do not callGodotSharpCleanup.CollectPendingFinalizers()orGodotObjectLifecycle.CollectPendingFinalizers()from ordinary test runners; register Godot runtime graphs with the appropriate owner scope and let the centralized exit path drain known owners. - Use
SnapshotTestRuntimefor snapshot renderer tests instead of rebuilding a fake runtime source from scratch. - Reuse deterministic damage resolvers in
tests/shared/and domain helpers intests/battle_runtime/helpers/before adding new battle test doubles. - Use
HeadlessGameTestSession.GetGameSessionTyped()/GetRuntimeFacadeTyped()and typed runtime APIs. Do not route formal test setup throughGodotObject.Call(...)or string method names when typed APIs exist. - Use
GameTextCommandRunnerfor text automation flows and callDispose(true)when finished. - Put repeated helpers in
tests/shared/or the nearest domain helper folder only after at least two tests need them. Keep one-off builders local to the runner.
Write The Runner
- Place the test beside its domain:
tests/warehouse,tests/equipment,tests/progression,tests/runtime,tests/world_map,tests/text_runtime, ortests/battle_runtime. - Name C# runners
run_<behavior>_regression.cs. Do not manually create or edit.uidfiles. - Use a
public partial class run_<behavior>_regression : LifecycleTestSceneTreewith a privateTestHarness. - In
_Initialize(), useRunAfterProcessStartup(Run)when the test needs autoloads, scene tree readiness, the processContentSnapshot, async waits, or Godot resources that should settle before assertions. DirectRun()is acceptable for isolated pure logic runners. Do not use string-basedCallDeferred(nameof(...))dispatch. When a runner usesasync voidas theRunAfterProcessStartup(...)callback, wrap its awaited body intry/catch/finally, record unexpected exceptions inTestHarness, and callRequestTestExit(...)fromfinally; otherwise Godot can log the exception while the SceneTree keeps running until the outer timeout. - Split assertions into small private methods named for the contract being protected.
- Build the smallest fixture that exercises the behavior. Prefer typed setup APIs and formal content injection helpers already present in the codebase.
- Dispose owned sessions, runtimes, registries, windows, resources, and services in
finallyblocks when cleanup affects later assertions or finalizers, but do not run a local forced-GC/finalizer drain there. - If the runtime relationship, ownership boundary, or recommended read set changed, update
docs/design/project_context_units.mdafter the code change.
Assert These Things
Assert stable contracts and failure modes:
- Command success/failure, typed result code, and stable error code.
- Public typed API output, owner-visible state transition, and mutation/no-mutation behavior.
- Snapshot fields and short stable text fragments that are part of the automation surface.
- Payload boundary normalization, rejection, defensive copy behavior, lifecycle cleanup, save locks, and content catalog binding when those are the intended contracts.
- Cross-table validation errors by domain and count when the validator surface defines those counts.
Private fields are allowed only when the existing project exposes no cleaner setup seam and the test is explicitly an architecture or ownership contract regression. Keep the assertion tied to the observable contract being protected, not incidental storage shape.
Do Not Assert These Things
Avoid brittle or misleading coverage:
- Do not assert private cache identity, backing collection type, helper call order, or internal field layout unless the change is specifically an ownership, defensive-copy, or stale-reference contract.
- Do not assert full log dumps, full text snapshots, full rendered UI text, or incidental Chinese/English phrasing unless the text surface itself is the contract. Prefer fields, stable event IDs, error codes, and short fragments.
- Do not assert exact RNG outcomes, AI score totals, target ordering, benchmark timing, or battle balance numbers in routine regressions.
- Do not duplicate production enum validation, legal-value
HashSets, schema allowlists, or rule tables inside tests. Test the production owner API instead. - Do not read source files or serialized resource files as text to assert implementation tokens. Put static architecture constraints in analyzers or review rules; verify authored resources through the production loader/registry and runtime contracts through typed owner behavior.
- Do not drive formal runtime behavior through
GDictionaryoptions, public Godot dictionary projections, string-key fallback, orGodotObject.Call(...)when the repo has typed APIs for that path. - Do not add compatibility tests for old payloads, legacy aliases, fallback migrations, or old schema support without explicit user confirmation.
- Do not make tests depend on
.godot/,.uid, generated cache files, local save artifacts, benchmark output, or personal capture artifacts.
Validate
Run the narrowest relevant validation. After editing any C# source or C# runner, build before the first Godot headless run. Godot may otherwise execute the previously compiled assembly and report a false pass for a test that was not compiled yet:
dotnet build magic.csproj
godot --headless --script tests/<domain>/run_<behavior>_regression.cs
For a domain sweep, use:
python tests/run_regression_suite.py --pattern tests/<domain>
For application E2E, validate the outer runner separately after the build:
python tests/tooling/test_run_e2e_suite.py
python tests/run_e2e_suite.py --scenario <name> --fail-on-output-error
Do not add tests/e2e/ to the routine regression sweep. These scenarios own isolated process-level user data and must remain explicit, serialized, and opt-in.
Do not pass --include-simulation or --include-benchmarks unless the user explicitly requested those classes of tests.
Keep This Skill Current
After using this skill to write, revise, or review tests, compare the actual workflow against these instructions before the final response. If the task revealed a reusable process improvement, missing shared helper rule, assertion boundary, validation command, or anti-pattern, update .codex/skills/godot-test-writing/SKILL.md in the same work before finishing.
Do not update the skill for one-off facts that only apply to a single bug or temporary local artifact. Update it when the lesson should guide future test-writing tasks in this repository.
When not to use it
- →When the user explicitly asks for routine numeric simulation, balance, benchmark, or analysis runners
- →When the test requires asserting private cache identity, backing collection type, or internal field layout unless it's an architecture contract regression
- →When the test requires asserting full log dumps, full text snapshots, or incidental phrasing
Limitations
- →The skill does not include routine numeric simulation, balance, benchmark, or analysis runners unless explicitly asked.
- →The skill does not assert private cache identity, backing collection type, or internal field layout unless the change is specifically an architecture or ownership contract regression.
- →The skill does not assert full log dumps, full text snapshots, or incidental Chinese/English phrasing unless the text surface itself is the contract.
How it compares
This skill guides the creation of focused, maintainable regression tests within a specific Godot 4.6 C# project by enforcing architectural units, test layers, and shared fixtures, unlike general test writing practices.
Compared to similar skills
godot-test-writing side by side with the closest alternatives in the catalog.
| Skill | Installs | Updated | Safety | Difficulty |
|---|---|---|---|---|
| godot-test-writing (this skill) | 0 | 1mo | Review | Advanced |
| csharp-pro | 9 | 3mo | No flags | Intermediate |
| performance-benchmark | 3 | 4mo | No flags | Intermediate |
| backend-testing | 3 | 12d | No flags | Intermediate |
Try saying
Example prompts that trigger this skill in your AI assistant.
You might also like
csharp-pro
sickn33
Write modern C# code with advanced features like records, pattern matching, and async/await. Optimizes .NET applications, implements enterprise patterns, and ensures comprehensive testing. Use PROACTIVELY for C# refactoring, performance optimization, or complex .NET solutions.
performance-benchmark
dotnet
Generate and run ad hoc performance benchmarks to validate code changes. Use this when asked to benchmark, profile, or validate the performance impact of a code change in dotnet/runtime.
backend-testing
exceptionless
Backend testing with xUnit, Foundatio.Xunit, integration tests with AppWebHostFactory, FluentClient, ProxyTimeProvider for time manipulation, and test data builders. Keywords: xUnit, Fact, Theory, integration tests, AppWebHostFactory, FluentClient, ProxyTimeProvider, TimeProvider, Foundatio.Xunit, TestWithLoggingBase, test data builders
dotnet-dev
GitTools
Expert guidance for .NET development in this repository. Use this skill for building, testing, debugging, and understanding project structure, coding conventions, dependency injection patterns, and testing practices.
mutation-testing
SebastienDegodez
Use when running mutation testing, killing mutants, verifying test quality, checking mutation score, or analyzing survivors after the test baseline is green
quality-ci
managedcode
Set up or refine open-source .NET code-quality gates for CI: formatting, `.editorconfig`, SDK analyzers, third-party analyzers, coverage, mutation testing, architecture tests, and security scanning. USE FOR: .NET quality gates in CI; analyzer, coverage, mutation, and architecture-test choices; stand