GodotUnit.Cli
0.0.0-alpha.0.69
dotnet tool install --global GodotUnit.Cli --version 0.0.0-alpha.0.69
dotnet new tool-manifest
dotnet tool install --local GodotUnit.Cli --version 0.0.0-alpha.0.69
#tool dotnet:?package=GodotUnit.Cli&version=0.0.0-alpha.0.69&prerelease
nuke :add-package GodotUnit.Cli --version 0.0.0-alpha.0.69
GodotUnit
A test framework for Godot 4+ C# projects. Uses source generation for reflection-free test discovery and provides Godot-specific utilities for scene/node testing.
Components
| Package | Description |
|---|---|
| GodotUnit.Runtime | Test attributes, runner, and Godot integration |
| GodotUnit.Generator | Source generator for test discovery |
| GodotUnit.Cli | Native AOT CLI for running tests and tracking history |
| GodotUnit.Analyzers | Code analyzers for test quality |
Quick Start
Add the NuGet packages to your Godot project:
<PackageReference Include="GodotUnit.Runtime" Version="*" />
<PackageReference Include="GodotUnit.Generator" Version="*" OutputItemType="Analyzer" />
Write a test:
using GodotUnit;
public partial class PlayerTests
{
[Before(HookType.Test)]
public void Setup()
{
// runs before each test
}
[Test]
public async Task Player_TakesDamage_HealthDecreases()
{
var player = TestContext.Current.AddNode(new Player());
player.TakeDamage(10);
await TestContext.Current.WaitPhysicsFrame();
Assert.That(player.Health).IsEqualTo(90);
}
[Test]
[Arguments(1, 2, 3)]
[Arguments(5, 5, 10)]
public void Add_ReturnsSum(int a, int b, int expected)
{
Assert.That(a + b).IsEqualTo(expected);
}
}
Run tests from your game's entry point:
public override async void _Ready()
{
await GodotUnit.GodotUnit.RunTests(this, TestRegistry.TestClasses, OS.GetCmdlineArgs());
}
Attributes
| Attribute | Description |
|---|---|
[Test] |
Marks a test method |
[Before(HookType)] |
Setup - HookType.Test (per-test) or HookType.Class (once, must be static) |
[After(HookType)] |
Teardown - same as Before |
[Arguments(...)] |
Parameterized test data (multiple allowed) |
[Category("name")] |
Test categorization for filtering |
[Skip("reason")] |
Skip test with optional reason |
[Timeout(ms)] |
Per-test timeout in milliseconds |
[Parallel] |
Class-level - enables parallel execution (for pure unit tests only) |
[RequiresDisplay] |
Auto-skipped in headless mode |
TestContext
Access via TestContext.Current during test execution:
// Scene tree access
TestContext.Current.SceneTree
TestContext.Current.TestScene
// Frame processing
await TestContext.Current.WaitPhysicsFrame();
await TestContext.Current.WaitProcessFrame();
await TestContext.Current.ProcessFrames(5);
await TestContext.Current.WaitSeconds(2.0);
// Node management (auto-cleanup after test)
var node = TestContext.Current.AddNode(new MyNode());
var scene = await TestContext.Current.LoadSceneAsync<MyScene>("res://scene.tscn");
// Test metadata
TestContext.Current.Metadata.TestName
TestContext.Current.CancellationToken
Nodes added via TestContext are automatically removed after each test.
CLI Tool
Install:
dotnet tool install -g GodotUnit.Cli
Commands:
# Run tests
godotunit run --all # all tests (excludes RequiresDisplay)
godotunit run @Combat # namespace filter (contains)
godotunit run #Integration # category filter
godotunit run PlayerTests # class name filter
godotunit run --rerun-failed # rerun from failed-tests.json
godotunit run --display # RequiresDisplay tests only
# Parallel execution
godotunit run-parallel # 8 workers default
godotunit run-parallel --workers 4 # custom worker count
godotunit run-parallel --dry-run # show partition plan
# Query test history
godotunit query runs # recent test runs
godotunit query history <pattern> # history for test pattern
godotunit query flaky # tests below 90% pass rate
godotunit query slowest # slowest by avg duration
# Analyze failures
godotunit analyze # failure summary
godotunit analyze --show 1 # detail for failure #1
godotunit analyze --show 1 --with-logs # include logs
godotunit analyze --exceptions # group by exception type
# Track flakiness
godotunit track PlayerTests --runs 10 # run N times, report pass rate
Filtering
The CLI supports multiple filter types:
@Namespace- namespace contains match#Category- category exact match!#Category- exclude categoryClassName- class name contains matchClass::Method- specific test methodMethod*- wildcard pattern
Configuration
Priority: CLI flags > godotunit.json > GODOT_PATH env var
{
"godotPath": "/path/to/godot.exe",
"projectPath": "src/godot"
}
Architecture
The source generator scans for [Test], [Before], and [After] attributes at compile time and generates:
ITestInvokerimplementation for each test class - enables reflection-free test executionTestRegistrywith metadata for all discovered tests
This approach avoids runtime reflection and provides deterministic test ordering based on source line numbers.
Exception Handling
Godot swallows exceptions thrown in _Ready() callbacks. GodotUnit captures these via AppDomain.FirstChanceException and surfaces them as ReadyCallbackException, ensuring test failures are properly reported.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
This package has no dependencies.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.0.0-alpha.0.69 | 94 | 3/20/2026 |
| 0.0.0-alpha.0.63 | 68 | 3/20/2026 |