Skip to content
cccskills
FreePublished on GitHub

godot-testing

Use when writing tests for Godot projects — TDD workflow with GUT and gdUnit4, covers both GDScript and C#

The English summary is being prepared. Showing the original description.

See how to install

Files included (6)

  • SKILL.md9.7 KB
  • gdunit4-reference.md10.5 KB
  • gut-reference.md8.6 KB
  • references/running-tests.md3.2 KB
  • references/tdd-workflow.md5.9 KB
  • references/testing-patterns.md5.0 KB

SKILL.md (original)

Review the instructions the agent will receive before you install.

Godot Testing

This skill covers test-driven development (TDD) for Godot 4.3+ projects using GUT (Godot Unit Testing) and gdUnit4. It includes framework selection, full RED-GREEN-REFACTOR examples, test structure, running tests in CI, and common testing patterns.

Related skills: godot-code-review for review checklists, dependency-injection for test-friendly architecture, export-pipeline for CI/CD test automation.

Framework Selection

FeatureGUTgdUnit4
LanguageGDScript-first, limited C#GDScript + C# (first-class)
InstallAssetLib or git submoduleAssetLib or git submodule
Editor integrationBuilt-in GUT panelBuilt-in inspector + panel
Mockingdouble() / stub() APImock() / spy() API
Scene testingadd_child_autofree()auto_free() + scene runner
CI supportgut_cmdln.gd CLI scriptruntest.sh / GdUnitCmdTool.gd
C# supportMinimal (GDScript wrappers only)Native C# assertions + lifecycle
MaturityEstablished (Godot 3 + 4)Godot 4 focused, actively updated
Best forPure GDScript projectsMixed GDScript/C# or C#-only

Rule of thumb: Use GUT for GDScript-only projects. Use gdUnit4 for C# projects or when you need first-class C# support and scene runner utilities.


TDD Workflow: RED-GREEN-REFACTOR

The standard Test-Driven Development cycle: write a failing test (RED), write minimal code to pass (GREEN), then refactor without breaking the test. Each step has its own discipline — don't skip RED (you'll write tests that pass trivially), and don't skip REFACTOR (technical debt compounds).

See references/tdd-workflow.md for a worked GDScript + C# example walking through all three steps on a HealthComponent.


Test Directory Structure

res://
├── .gutconfig.json                       # GUT default config file (optional)
├── src/
│   └── components/
│       ├── health_component.gd
│       └── HealthComponent.cs
└── tests/
    ├── unit/
    │   ├── test_health_component.gd      # GUT: test_ prefix (default -gprefix)
    │   └── HealthComponentTest.cs        # gdUnit4 C#: [TestSuite] attribute
    └── integration/
        ├── test_player_scene.gd
        └── PlayerSceneTest.cs

Naming conventions

FrameworkGDScript fileC# fileTest method prefix/attribute
GUTtest_*.gdN/Afunc test_*()
gdUnit4any name (*_test.gd when generated)*Test.csfunc test_*() / [TestCase]

Running Tests

Both frameworks ship a CLI runner. GUT: addons/gut/gut_cmdln.gd invoked via godot --headless --path . -s addons/gut/gut_cmdln.gd -gexit (without -gexit the run never quits). gdUnit4: addons/gdUnit4/runtest.sh -a res://tests (wraps bin/GdUnitCmdTool.gd; under --headless it also needs --ignoreHeadlessMode), or the editor's GdUnit dock. CI: tag-triggered or PR-triggered GitHub Action that installs Godot, runs the suite, exits non-zero on failure.

See references/running-tests.md for full GUT and gdUnit4 CLI invocations + a copy-pasteable GitHub Actions workflow.


Testing Patterns

Four common patterns: scenes with nodes (instantiate via add_child in before_each, free in after_each), signal testing (assert that emitting works and connect-then-emit fires), mocking/doubling (gdUnit4 mock() in GDScript; in C#, hand-rolled fakes via @export injection), async (await yields, signals, frames in tests).

See references/testing-patterns.md for full code on each pattern (GDScript + C# where applicable).


Common Assertions

GUT assertions

AssertionDescription
assert_eq(actual, expected)Equality
assert_ne(actual, expected)Not equal
assert_true(value)Is truthy
assert_false(value)Is falsy
assert_null(value)Is null
assert_not_null(value)Is not null
assert_gt(actual, expected)Greater than
assert_lt(actual, expected)Less than
assert_gte(actual, expected)Greater than or equal
assert_lte(actual, expected)Less than or equal
assert_has(collection, item)Collection contains item
assert_does_not_have(collection, item)Collection does not contain item
assert_string_contains(str, sub)String contains substring
assert_almost_eq(actual, expected, margin)Float equality within margin
assert_signal_emitted(obj, signal_name)Signal was emitted
assert_signal_not_emitted(obj, signal_name)Signal was not emitted

gdUnit4 assertions (GDScript + C#)

GDScriptC#Description
assert_that(val).is_equal(exp)AssertThat(val).IsEqual(exp)Equality
assert_that(val).is_not_equal(exp)AssertThat(val).IsNotEqual(exp)Not equal
assert_that(val).is_true()AssertThat(val).IsTrue()Is true
assert_that(val).is_false()AssertThat(val).IsFalse()Is false
assert_that(val).is_null()AssertThat(val).IsNull()Is null
assert_that(val).is_not_null()AssertThat(val).IsNotNull()Is not null
assert_that(val).is_greater(exp)AssertThat(val).IsGreater(exp)Greater than
assert_that(val).is_less(exp)AssertThat(val).IsLess(exp)Less than
assert_that(val).is_between(min, max)AssertThat(val).IsBetween(min, max)In range (inclusive)
assert_that(arr).contains([a, b])AssertThat(arr).Contains(a, b)Array contains elements
assert_that(str).contains("sub")AssertThat(str).Contains("sub")String contains substring
assert_that(val).is_equal_approx(exp, margin)AssertThat(val).IsEqualApprox(exp, margin)Float within margin
await assert_signal(mon).is_emitted("name")await AssertSignal(node).IsEmitted("name")Signal emitted

What NOT to Test

Avoid testing things that add noise without catching real bugs:

  • Godot engine internals — do not assert that Node.add_child() works or that @export variables show up in the editor
  • Private implementation details — test behavior through the public API; if a refactor breaks a test that covers only private state, the test is wrong
  • Visual/rendering output — pixel-level rendering results are brittle; test the data driving the visuals instead
  • Timing-sensitive floats without margins — use assert_almost_eq / IsEqualApprox for physics values
  • One-liners that wrap a built-in — a property getter that just returns a field needs no test
  • Every possible invalid input — test the documented contract, not every imaginable misuse

Checklist

  • Each test file matches the naming convention for the chosen framework (GUT test_*.gd; gdUnit4 *_test.gd / *Test.cs)
  • Tests extend the correct base class (GutTest / GdUnitTestSuite); C# gdUnit4 suites are plain [TestSuite] classes
  • C#: gdUnit4.api pinned to 4.3.x on Godot 4.3; on 5.x (Godot 4.4+), suites that touch nodes or scenes carry [RequireGodotRuntime]
  • Nodes added to the scene tree use add_child_autofree or auto_free — never manual queue_free()
  • Signals are watched before the action that triggers them
  • Mocks/doubles are used for external dependencies, not for the unit under test
  • Each test covers exactly one behavior (one logical assertion per test)
  • CI workflow runs tests headlessly on every push and PR
  • Flaky async tests use explicit timeouts, not arbitrary sleep durations
  • Tests pass before merging (RED is only acceptable while actively implementing)

Reviews

No reviews yet. Tell others what you thought.

Comments

No login needed. Share how it worked for you, ask a question, or note where it did not run.

No comments yet. Be the first to write one.

Comments are published right away. Do not include personal information such as email addresses or phone numbers. Up to 2 URLs.

0 / 1,000 characters

This form is protected by reCAPTCHA, and the Google Privacy Policy and Terms of Service apply.

More skills from this repository

Use when working with 2D-specific systems — TileMaps, parallax scrolling, 2D lights and shadows, canvas layers, particles 2D, custom drawing, and 2D meshes in Godot 4.3+

The English summary is being prepared. Showing the original description.

jame581/GodotPrompter862Updated Oct 22, 2026

Use when working with 3D-specific systems — materials, lighting, shadows, environment, global illumination, fog, LOD, occlusion culling, and decals in Godot 4.3+

The English summary is being prepared. Showing the original description.

jame581/GodotPrompter862Updated Oct 22, 2026

Use when building character abilities — Resource-based abilities with cost/cooldown/cast, buffs/debuffs, stat modifiers, gameplay tags, and HUD binding

The English summary is being prepared. Showing the original description.

jame581/GodotPrompter862Updated Oct 22, 2026

Use when creating Godot editor plugins — EditorPlugin, @tool scripts, custom inspectors, and dock panels

The English summary is being prepared. Showing the original description.

jame581/GodotPrompter862Updated Oct 22, 2026

Use when implementing AI movement — NavigationAgent2D/3D, steering behaviors, behavior trees, and patrol patterns

The English summary is being prepared. Showing the original description.

jame581/GodotPrompter862Updated Oct 22, 2026

Use when implementing animations — AnimationPlayer, AnimationTree, blend trees, state machines, sprite animation, and code-driven animation

The English summary is being prepared. Showing the original description.

jame581/GodotPrompter862Updated Oct 22, 2026

See all skills by jame581

Report a problem with this skill