2dog.xunit 4.7.2.110

There is a newer version of this package available.
See the version list below for details.
dotnet add package 2dog.xunit --version 4.7.2.110
                    
NuGet\Install-Package 2dog.xunit -Version 4.7.2.110
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="2dog.xunit" Version="4.7.2.110" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="2dog.xunit" Version="4.7.2.110" />
                    
Directory.Packages.props
<PackageReference Include="2dog.xunit" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add 2dog.xunit --version 4.7.2.110
                    
#r "nuget: 2dog.xunit, 4.7.2.110"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package 2dog.xunit@4.7.2.110
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=2dog.xunit&version=4.7.2.110
                    
Install as a Cake Addin
#tool nuget:?package=2dog.xunit&version=4.7.2.110
                    
Install as a Cake Tool

2dog.xunit

xUnit collection definitions for testing Godot applications with 2dog.

The fixtures themselves (Fixture, HeadlessFixture, and FixtureBase) ship in the 2dog.engine package under twodog.Testing. This package adds the xUnit-specific glue.

What it provides

  • RenderingCollection - binds the rendering-enabled Fixture
  • HeadlessCollection - binds HeadlessFixture (use this for CI)

Both set DisableParallelization = true, because normal hosting allows one active Godot instance per assembly load context. These collections share that context and run sequentially.

New test hosts scaffold as <Name>.xunit; existing .tests hosts and custom names remain supported. The template includes eight examples covering async/await, Godot signal awaits, signal arguments and counts, timers, enter/exit-tree signals, deferred work and QueueFree.

Waits and assertions

Use these helpers on the fixture's engine thread (twodog.Testing.Xunit):

  • await godot.AwaitAsync(task, cancellationToken: TestContext.Current.CancellationToken) pumps frames and propagates the task's result or failure.
  • await godot.WaitUntilAsync(() => condition, cancellationToken: TestContext.Current.CancellationToken) pumps until a condition holds.
  • using var signal = GodotAssert.ExpectSignal(node, Node.SignalName.TreeEntered) subscribes immediately. Call signal.AssertEmitted() for exactly one emission, or await signal.WaitAsync(godot, cancellationToken: TestContext.Current.CancellationToken) to wait for one.
  • GodotAssert.ExpectSignal<Node>(parent, Node.SignalName.ChildEnteredTree) records a single argument per emission in Values.
  • await GodotAssert.FreedAsync(godot, node, cancellationToken: TestContext.Current.CancellationToken) asserts actual deletion after QueueFree.

Waits default to five seconds, honor xUnit cancellation, and allow one active pump per fixture. Expectations disconnect on disposal, timeout or cancellation; disposal does not assert. A timed-out AwaitAsync does not cancel its supplied task. Free native nodes in finally; disposing a node's C# wrapper does not free it. See testing documentation for examples and ownership rules.

How it works

xUnit only discovers [CollectionDefinition] classes that live in the test assembly – a definition shipped in a referenced DLL is silently ignored (its DisableParallelization and ICollectionFixture<T> are not applied). To make the collections actually work, this package ships them as compile-in source: a build/2dog.xunit.targets file adds the collection definitions to your test project's compilation, so they end up in your test assembly where xUnit can find them.

You therefore do not write your own collection definition – just reference the package and use the collections directly.

Usage

using Godot;
using twodog.Testing;
using twodog.Testing.Xunit;
using Xunit;

[Collection<HeadlessCollection>]
public class MyTests(HeadlessFixture godot)
{
    [Fact]
    public void EngineStarts()
    {
        Assert.NotNull(godot.Tree);
    }
}

Godot's thread

Each collection that uses a 2dog fixture runs on the 2dog test thread: the engine starts there, and the tests, their await continuations, and the fixture's disposal stay on it, as Godot requires. Between tests, the thread also runs the continuations Godot queued for its frame loop. Tests without a 2dog fixture keep xUnit's usual threads.

  • On macOS the 2dog test thread is the process main thread, because AppKit aborts a windowed engine started anywhere else. For this, the package makes the test assembly's entry point wrap the one xUnit generates: xUnit's runner moves to a thread of its own, and the main thread runs the 2dog collections, one at a time.
  • Elsewhere each collection gets a new thread. On Windows it is STA, which Godot's windowing needs for OLE drag-and-drop.

This is done by a test framework registered for the test assembly, plus that entry point. If you need your own test framework, set <TwoDogGodotTestThread>false</TwoDogGodotTestThread>, which leaves out both. On macOS, windowed fixtures then abort unless that framework runs their collections through GodotTestThread.Run, from an entry point that calls GodotTestThread.RunMain.

A project with its own entry point (<XunitAutoGeneratedEntryPoint>false</XunitAutoGeneratedEntryPoint>, or a StartupObject) keeps it. On macOS it then has to run xUnit through GodotTestThread.RunMain, or windowed fixtures abort the test process:

using twodog.Testing.Xunit;

internal static class Program
{
    public static int Main(string[] args) => GodotTestThread.RunMain(
        () => Xunit.Runner.InProc.SystemConsole.ConsoleRunner.Run(args).GetAwaiter().GetResult());
}

The package also gives test projects the comctl32 v6 application manifest that godot.exe has, unless the project sets its own ApplicationManifest. Without it, Godot's Windows display server warns about common controls.

Godot errors fail tests

Every error and warning Godot reports during a test fails that test, including push_error, failed engine checks, and exceptions Godot catches in C# callbacks (which it otherwise only prints). This applies to every test that runs on a 2dog fixture; plain unit tests without an engine are left alone.

A test that expects an error consumes it, which also asserts its text:

[Fact]
public void RejectsNegativeHealth()
{
    player.Health = -1;
    godot.Errors.Expect("Health must not be negative");
}

Errors reported between tests (engine startup, or deferred work an earlier test left behind) fail the next test that runs on a fixture, with a message saying so.

To opt out, mark a test or class [AllowGodotErrors], or turn the check off for the whole project:

<PropertyGroup>
    <TwoDogFailOnGodotErrors>false</TwoDogFailOnGodotErrors>
</PropertyGroup>

Custom fixtures

Need a different Godot configuration? Subclass FixtureBase and write a one-line collection for it in your own test project:

using twodog.Testing;
using Xunit;

public class OpenGl3Fixture() : FixtureBase("--rendering-driver", "opengl3");

[CollectionDefinition(nameof(OpenGl3Collection), DisableParallelization = true)]
public class OpenGl3Collection : ICollectionFixture<OpenGl3Fixture>;
There are no supported framework assets in this package.

Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
4.7.2.113 0 10/10/2026
4.7.2.112 0 10/10/2026
4.7.2.110 48 10/9/2026
4.7.2.109 57 10/9/2026
4.7.2.105 313 10/5/2026
4.7.2.103 353 10/3/2026
4.7.2.102 93 10/3/2026
4.7.2.99 95 10/2/2026
4.7.2.98 108 10/2/2026
4.7.2.97 88 10/2/2026
Loading failed