Chickensoft.GoDotTest 0.0.2

There is a newer version of this package available.
See the version list below for details.
dotnet add package Chickensoft.GoDotTest --version 0.0.2                
NuGet\Install-Package Chickensoft.GoDotTest -Version 0.0.2                
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="Chickensoft.GoDotTest" Version="0.0.2" />                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add Chickensoft.GoDotTest --version 0.0.2                
#r "nuget: Chickensoft.GoDotTest, 0.0.2"                
#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.
// Install Chickensoft.GoDotTest as a Cake Addin
#addin nuget:?package=Chickensoft.GoDotTest&version=0.0.2

// Install Chickensoft.GoDotTest as a Cake Tool
#tool nuget:?package=Chickensoft.GoDotTest&version=0.0.2                

GoDotTest

Discord line coverage branch coverage

An opinionated test runner system to make running C# tests easier in Godot. Supports code coverage and debugging in-editor.

Installation

Find the latest version of GoDotTest on nuget.

Add the latest version of GoDotTest to your *.csproj file. Make sure to replace *VERSION* with the latest version.

<ItemGroup>
  <PackageReference Include="Chickensoft.GoDotTest" Version="*VERSION*" />
</ItemGroup>

You can use GoDotTest with C# 10 and Godot to run, debug, and collect code coverage for your project inside Godot.

For C# 10 to work, you need the dotnet 6 SDK installed. See what you have installed with dotnet --info. On mac, Godot 3 can have trouble finding .NET 6 if you have older SDK's installed, due to the dotnet path search order. There are also a few work-arounds available.

This project uses git submodules to bring in the code for the Godot addons, since some of the addons are still in development. Be sure to run git submodule update --init --recursive once you've cloned the repo to pull in all the addon code.

Example Test

Here's a simple test which does absolutely nothing. It can use the TestScene node available to it from its base class to manipulate the scene tree, if needed.

using Godot;
using GoDotNet;
using GoDotTest;

public class ExampleTest : TestClass {
  private readonly ILog _log = new GDLog(nameof(ExampleTest));

  public ExampleTest(Node testScene) : base(testScene) { }

  [SetupAll]
  public void SetupAll() => _log.Print("Setup everything");

  [Setup]
  public void Setup() => _log.Print("Setup");

  [Test]
  public void Test() => _log.Print("Test");

  [Cleanup]
  public void Cleanup() => _log.Print("Cleanup");

  [CleanupAll]
  public void CleanupAll() => _log.Print("Cleanup everything");
}

Here's the output of the test above:

test output

Setup

You can debug tests in Godot from Visual Studio Code. To do this, you will need to specify the GODOT environment variable for the following launch configurations and scripts to work correctly. The GODOT variable should point to the path of the Godot executable.

You will need to include something like this in your .zshrc or .bash_profile file.

# Dotnet
export DOTNET_CLI_TELEMETRY_OPTOUT=1 # Disable analytics
DOTNET_ROOT="/usr/local/share/dotnet"
# Mono
export PATH="/Library/Frameworks/Mono.framework/Versions/Current/Commands/mono:$PATH"
export PATH="$HOME/.dotnet/tools:$PATH"
# For dotnet 6 SDK:
export PATH="/usr/local/share/dotnet:/usr/local/share/dotnet/sdk:$PATH"
# Godot
# Path go Godot executable, on mac it might look like this:
export GODOT="/Applications/Godot.app/Contents/MacOS/Godot"

Debugging

The following launch.json file provides launch configurations to debug the game, debug all the tests, or debug the currently open test in Visual Studio Code. To debug the currently open test, make sure the class name of the test matches the file name, as is typical in C#.

You can also just copy and paste .vscode/launch.json and .vscode/tasks.json from this repository into your own project that uses GoDotTest.

{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "Play in Editor",
      "type": "godot-mono",
      "mode": "playInEditor",
      "request": "launch"
    },
    // We tell the game to run tests by using command line arguments.
    // This means we can't use the "play in editor" option — we have to launch
    // our own instance of Godot.
    //
    // Since passing scene files to Godot doesn't seem to work easily with the
    // C# Tools for Godot VSCode plugin, we use the path to Godot from the
    // environment. Make sure you set the GODOT variable to your Godot
    // executable.
    //
    // On mac, you can add the following to your zsh rc file:
    // alias godot="/Applications/Godot.app/Contents/MacOS/Godot"
    {
      "name": "Debug Tests",
      "type": "godot-mono",
      "mode": "executable",
      "request": "launch",
      "executable": "${env:GODOT}",
      "executableArguments": [
        "--run-tests",
        "--quit-on-finish"
      ],
      "preLaunchTask": "build"
    },
    // Debug the current test!
    //
    // The test runner will look for the class with the same name as the test
    // file that's currently open (disregarding its folder and file extension).
    // The search is case-insensitive.
    {
      "name": "Debug Current Test",
      "type": "godot-mono",
      "mode": "executable",
      "request": "launch",
      "executable": "${env:GODOT}",
      "executableArguments": [
        "--run-tests=${fileBasenameNoExtension}",
        "--quit-on-finish"
      ],
      "preLaunchTask": "build"
    },
    {
      "name": "Launch",
      "type": "godot-mono",
      "request": "launch",
      "mode": "executable",
      "preLaunchTask": "build",
      "executable": "/Applications/Godot.app/Contents/MacOS/Godot",
      "executableArguments": [
        "--path",
        "${workspaceRoot}"
      ]
    },
    {
      "name": "Launch (Select Scene)",
      "type": "godot-mono",
      "request": "launch",
      "mode": "executable",
      "preLaunchTask": "build",
      "executable": "/Applications/Godot.app/Contents/MacOS/Godot",
      "executableArguments": [
        "--path",
        "${workspaceRoot}",
        "${command:SelectLaunchScene}"
      ]
    },
    {
      "name": "Attach",
      "type": "godot-mono",
      "request": "attach",
      "address": "localhost",
      "port": 23685
    }
  ]
}

Note: You will also need the accompanying tasks.json (below) to be able to build the game before running the debug configurations for testing.

{
  "version": "2.0.0",
  "tasks": [
    {
      "label": "build",
      "command": "dotnet",
      "type": "process",
      "args": [
        "build"
      ],
      "problemMatcher": "$msCompile",
      "presentation": {
        "echo": true,
        "reveal": "silent",
        "focus": false,
        "panel": "shared",
        "showReuseMessage": true,
        "clear": false
      }
    }
  ]
}

Test Scene

Create a test folder in your project and create a test scene in it. Add a C# script to the root of the test scene with the following contents:

using Godot;
using GoDotNet;
using GoDotTest;

public class Tests : Node2D {
  public override async void _Ready() => await GoTest.RunTests(
    Assembly.GetExecutingAssembly(),
    this, TestEnvironment.From(OS.GetCmdlineArgs()), new GDLog(nameof(Tests))
  );
}

Main Scene

In your main scene, you need to determine if tests should be run. GoDotTest relies on the presence of certain command line arguments to determine if tests should be run.

In your main scene, you should construct a test environment from the command line arguments and determine if tests should be run. If they are, you can switch to the test scene. Otherwise, you can switch to the game scene. If you've written your own scene switching system, you can adapt this file to use that accordingly.

using Godot;
using GoDotTest;

public class Main : Node2D {
  public override void _Ready() {
    var testEnv = TestEnvironment.From(OS.GetCmdlineArgs());
    if (testEnv.ShouldRunTests) {
      GetTree().ChangeScene("res://test/Tests.tscn");
    }
    else {
      GetTree().ChangeScene("res://scenes/Game.tscn");
    }
  }
}

Logging

Make sure you add this to your project.godot file so you can see test logs when they're running.

[network]

; Required to see all the logs when tests are running!

limits/debugger_stdout/max_chars_per_second=200000
limits/debugger_stdout/max_messages_per_frame=500
limits/debugger_stdout/max_errors_per_second=500
limits/debugger_stdout/max_warnings_per_second=500

Assertions and Mocking

GoDotTest doesn't provide any assertions or mocking. It's simply a test provider and test running system. Eventually, GoDotTest will include a few asynchronous utilities to make integration testing scenes easier, allowing you to simulate frames, input, etc, but there are no plans to ever provide an assertion or mocking system — you can use whatever you like!

Coverage

If your code is configured correctly to switch to the test scene when --run-tests is passed in (see above), you can run all of your tests and generate code coverage while Godot is running.

test coverage

First, install coverlet and reportgenerator.

dotnet tool install --global dotnet-reportgenerator-globaltool
dotnet tool install --global coverlet.console
# Do this too if you're on an M1 mac / ARMx64 system:
# Works around https://github.com/dotnet/efcore/issues/27787#issuecomment-1110061226
dotnet tool update --global coverlet.console

To run Godot with code coverage enabled, use a script like the following (or reference the local coverage.sh.

coverlet .mono/temp/bin/Debug/ --target $GODOT --targetargs \
  "--run-tests --quit-on-finish" --format "lcov" \
  --output ./coverage/coverage.info \
  --exclude-by-file "**/test/**/*.cs" # Don't collect coverage for the tests

reportgenerator \
  -reports:"./coverage/coverage.info" \
  -targetdir:"./coverage/report" \
  -reporttypes:Html

# Open the coverage report in your browser.
open coverage/report/index.html

Note: On macOS, you may need to run chmod +x ./coverage.sh to add execution permissions before you are able to run the coverage.sh script.

How It Works

GoDotTest uses C# Reflection to find all classes in the current assembly that extend the TestClass it provides. It uses a TestProvider to find and load test suites (classes that extend TestClass) that can be run. It references a TestEnvironment that is created from the command line arguments given to the game/Godot and filters the test suites based on the presence of a test suite name, if given.

GoDotTest uses a TestExecutor to run methods in the order they are declared in a TestClass. Test methods are denoted with the [Test] attribute.

Test output is displayed by a TestReporter which responds to test events.

Auxiliary methods, such as Setup and Cleanup are run before and after each test, respectively. They can be specified with the [Setup] and [Cleanup] attributes on methods in a TestClass.

Additionally, any methods tagged with the [SetupAll] or [CleanupAll] attributes will be run once at the start of the test suite and once at the end, respectively.

GoDotTest will await any async Task test methods it encounters. Tests do not run in parallel, nor are there any plans to add that functionality. The focus of GoDotTest is to provide a simple, C#-first approach to testing in Godot that runs tests in a very simple and deterministic manner.

If you need to customize how tests are loaded and run, you can use the code in addons/go_dot_test/GoTest.cs as a starting point.

Command Line Arguments

  • --run-tests: The presence of this flag informs your game that tests should be run. If you've setup your main scene to redirect to the test scene when it finds this flag (as described above), you can use pass this flag in when running Godot from the command line (for debugging or CI/CD purposes) to run your test(s).
  • --quit-on-finish: The presence of this flag indicates that the test runner should exit the application as soon as it is finished running tests.
  • --stop-on-error: The presence of this flag indicates that the test runner should stop running tests when it encounters the first error in any test suite. Without this flag, it will attempt to run all of the test suites.
  • --sequential: The presence of this flag indicates that subsequent test methods in a test suite should be skipped if an error occurs in a test suite method. Use this if your test methods rely on the previous test method completing successfully. This flag is ignored when using --stop-on-error.

For more information about command line flags, see addons/go_dot_test/TestEnvironment.cs.

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
.NET Core netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.1 is compatible. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on Chickensoft.GoDotTest:

Package Downloads
RBG_GodotTools_AutoTest

RBG_GodotTools_AutoTest description.

GitHub repositories (3)

Showing the top 3 popular GitHub repositories that depend on Chickensoft.GoDotTest:

Repository Stars
chickensoft-games/GameDemo
The Chickensoft Game Demo — a fully tested, third-person 3D game built with Godot and C#. Now with saving and loading!
chickensoft-games/GodotEnv
Manage Godot versions and addons from the command line on Windows, macOS, and Linux.
chickensoft-games/AutoInject
Node-based dependency injection for C# Godot scripts at build-time, including utilities for automatic node-binding, additional lifecycle hooks, and .net-inspired notification callbacks.
Version Downloads Last updated
1.5.10 4,541 8/15/2024
1.5.9-godot4.3.0-rc.3 171 8/8/2024
1.5.8-godot4.3.0-rc.2 75 8/1/2024
1.5.7-godot4.3.0-rc.1 134 7/25/2024
1.5.6-godot4.3.0-beta.3 165 7/9/2024
1.5.5-godot4.3.0-beta.2 124 6/20/2024
1.5.4-godot4.3.0-beta.1 192 5/31/2024
1.5.3 1,487 5/15/2024
1.5.2 8,641 4/17/2024
1.5.1-godot4.2.2-rc.2 166 3/13/2024
1.5.0-godot4.2.2-rc.1 207 2/1/2024
1.4.1-godot4.2.2-rc.1 80 1/26/2024
1.4.0 3,883 12/18/2023
1.3.6 626 12/12/2023
1.3.5-godot4.2.1-rc.1 137 12/7/2023
1.3.4 1,112 11/30/2023
1.3.3-godot4.2.0-rc.2 112 11/25/2023
1.3.2-godot4.2.0-beta.5 600 11/7/2023
1.3.1-godot4.2.0-beta.3 100 10/27/2023
1.3.0-godot4.2.0-beta.2 97 10/20/2023
1.2.4-godot4.2.0-beta.2 81 10/19/2023
1.2.3 3,256 10/4/2023
1.2.2-godot4.1.2-rc.1 137 9/22/2023
1.2.1 506 9/4/2023
1.2.0 169 8/29/2023
1.1.19 235 8/21/2023
1.1.18 9,396 7/21/2023
1.1.17 1,296 7/7/2023
1.1.16-godot4.1.0-rc.3 145 7/4/2023
1.1.15-godot4.1.0-rc.2 145 6/30/2023
1.1.14-godot4.1.0-rc.1 130 6/27/2023
1.1.13-godot4.1.0-beta.3 121 6/22/2023
1.1.12-godot4.1.0-beta.2 119 6/14/2023
1.1.11-godot4.1.0-beta.1 116 6/7/2023
1.1.10 317 5/19/2023
1.1.9-godot4.0.3-rc.2 112 5/17/2023
1.1.8-godot4.0.3-rc.1 120 4/27/2023
1.1.7 601 4/4/2023
1.1.6-godot4.0.2-rc.1 805 4/3/2023
1.1.5 203 4/3/2023
1.1.4 1,182 4/3/2023
1.1.2-godot.4.beta.16 2,315 1/30/2023
1.1.2-beta8 183 12/17/2022
1.1.2-beta6 100 11/25/2022
1.1.2-beta.4.0.0.17 702 2/6/2023
1.1.2-beta.4.0.0.16 170 2/6/2023
1.1.1-beta6 96 11/25/2022
1.1.0-beta6 95 11/24/2022
1.0.0 507 9/17/2022
0.0.4 485 6/19/2022
0.0.3 404 6/19/2022
0.0.2 395 6/19/2022
0.0.1 440 6/19/2022

Initial release.