Skip to content

v5.0.0

Latest
Compare
Choose a tag to compare
@MikeSchulze MikeSchulze released this 21 Jun 09:07
· 6 commits to master since this release
39f8365

🚀 GdUnit4 v5.0.0 - Major Architecture Overhaul

Breaking Changes ⚠️

Test Engine Redesign: GdUnit4 v5.0.0 introduces a completely reworked test engine that no longer requires the Godot runtime by default. This significantly improves test performance and enables testing in CI/CD environments without Godot installations.

Migration Required: Existing tests that depend on Godot runtime features (scenes, nodes, resources, etc.) must now be explicitly marked with the [RequireGodotRuntime] attribute.

New Features ✨

🎯 Selective Godot Runtime

  • [RequireGodotRuntime]: Annotate classes or methods that need Godot runtime context
  • Tests without this attribute run in fast, lightweight mode
  • Dramatically improves test execution speed for logic-only tests

📊 Enhanced Debugging & Output

  • <CaptureStdOut>true</CaptureStdOut>: Capture console output and Godot prints in test results
  • [GodotExceptionMonitor]: Monitor and report exceptions from Godot's main thread:
    • Catches exceptions in node callbacks (_Ready, _Process, etc.)
    • Monitors scene tree operations
    • Reports "silent" Godot exceptions as test failures
  • [ThrowsException]: Comprehensive exception testing with precise validation
  • Better error reporting and diagnostics

🔧 Advanced Test Configuration

  • [DataPoint(nameof(DataSource))]: Create data-driven tests with support for:
    • Static properties and methods as data sources
    • Parameterized data methods with arguments
    • Async data sources with IAsyncEnumerable<object[]>
    • External class data sources
  • [ThrowsException(typeof(ArgumentException), "message")]: Verify expected exceptions with:
    • Exception type validation
    • Message matching
    • Source file and line number verification
    • Support for multiple expected exception types
  • Full VSTest filter support: Use standard test filtering in Visual Studio and dotnet test
  • [TestCategory("CategoryA")]: Organize tests with categories
  • [Trait("Category", "A")]: Add custom traits for test organization

Migration Guide 📋

Before v5.0.0:

[Test]
public void MyTest() 
{
    // All tests ran in Godot runtime
    var node = new Node();
    AddChild(node);
}

v5.0.0:

[Test]
public void MyLogicTest() 
{
    // Runs fast without Godot runtime
    var result = Calculator.Add(1, 2);
    AssertThat(result).IsEqual(3);
}

[Test]
[RequireGodotRuntime]  // ← Add this for Godot-dependent tests
public void MyGodotTest() 
{
    var scene = new PackedScene();
    var node = scene.Instantiate();
    AddChild(node);
}

[Test]
[RequireGodotRuntime]
[GodotExceptionMonitor]  // ← Monitor Godot exceptions
public void TestNodeCallback()
{
    var node = new MyNode(); // Will catch exceptions in _Ready()
    AddChild(node);
}

[Test]
[DataPoint(nameof(TestData))]  // ← Data-driven tests
public void TestCalculations(int a, int b, int expected)
{
    AssertThat(Calculator.Add(a, b)).IsEqual(expected);
}

[Test]
[ThrowsException(typeof(ArgumentNullException), "Value cannot be null")]
public void TestValidation()
{
    Calculator.Add(null, 5); // Expects specific exception
}

// Data source for parameterized tests
public static IEnumerable<object[]> TestData => new[]
{
    new object[] { 1, 2, 3 },
    new object[] { 5, 7, 12 }
};

Performance Impact 🚀

  • Non-Godot tests: Up to 10x faster execution
  • CI/CD friendly: No Godot installation required for logic tests
  • Selective runtime: Only pay the Godot overhead when needed

Key Attribute Features 🏷️

Data-Driven Testing

[Test]
[DataPoint(nameof(CalculationData))]
public void TestCalculations(int a, int b, int expected)
{
    AssertThat(Calculator.Add(a, b)).IsEqual(expected);
}

// Multiple data source options
public static IEnumerable<object[]> CalculationData => new[]
{
    new object[] { 1, 2, 3 },
    new object[] { 5, 7, 12 }
};

// Parameterized data methods
[DataPoint(nameof(GetDynamicData), 10)]
public static IEnumerable<object[]> GetDynamicData(int multiplier) => 
    Enumerable.Range(1, 3).Select(i => new object[] { i * multiplier });

// External data sources
[DataPoint(nameof(SharedTestData), typeof(TestDataProvider))]
public void TestWithExternalData(string input, bool expected) { }

Exception Testing

// Basic exception type verification
[Test]
[ThrowsException(typeof(ArgumentNullException))]
public void TestNullArgument() { }

// Message validation
[Test]
[ThrowsException(typeof(InvalidOperationException), "Operation not allowed")]
public void TestSpecificError() { }

// File and line verification
[Test]
[ThrowsException(typeof(ArgumentException), "Invalid value", "Calculator.cs", 25)]
public void TestPreciseLocation() { }

// Multiple possible exceptions
[Test]
[ThrowsException(typeof(ArgumentNullException))]
[ThrowsException(typeof(ArgumentException))]
public void TestMultipleExceptions() { }

Godot Integration

// Class-level runtime requirement
[RequireGodotRuntime]
public class NodeTests
{
    [Before]
    public void Setup() => Engine.PhysicsTicksPerSecond = 60;
}

// Method-level monitoring
[Test]
[RequireGodotRuntime]
[GodotExceptionMonitor]
public void TestNodeBehavior()
{
    var node = new MyCustomNode();
    AddChild(node); // Will catch exceptions in _Ready(), _Process(), etc.
}

.runsettings Configuration

<RunSettings>
  <GdUnit4>
    <CaptureStdOut>true</CaptureStdOut>
    <Parameters>--verbose --headless</Parameters>
    <DisplayName>FullyQualifiedName</DisplayName>
    <CompileProcessTimeout>30000</CompileProcessTimeout>
  </GdUnit4>
</RunSettings>

Summary

This release represents a major step forward in making GdUnit4 more efficient, flexible, and suitable for modern development workflows. The selective runtime approach allows developers to get the best of both worlds: lightning-fast tests for business logic and full Godot integration when needed.

Key Benefits:

  • Performance: Up to 10x faster for non-Godot tests
  • 🧪 Data-Driven: Comprehensive parameterized testing with multiple data source options
  • 🔍 Exception Testing: Precise exception validation with message and location verification
  • 🎮 Godot Integration: Smart runtime detection and exception monitoring
  • 🛠️ VSTest Compatible: Full integration with Visual Studio and dotnet test

For technical support and questions, please visit our GitHub repository or documentation.

What's Changed

✨ New Features

  • GD-138: Add capture test case execution stdout to the test report by @MikeSchulze in #139
  • GD-144: Add AwaitInputProcessed to SceneRunner by @MikeSchulze in #145
  • GD-46: Added support of DataPoint attributes, which make it possible to define parameterized tests with dynamic test data by @MikeSchulze in #147
  • GD-153: Add Roslyn Analyzer to validate TestCase and DataPoint attribute combinations by @MikeSchulze in #154
  • GD-156: Add an exception hook to report exceptions as test failures that are caught by Godot by @MikeSchulze in #157
  • GD-160: Apply runsettings environment variables to the test execution context by @MikeSchulze in #161
  • GD-163: Collect the Godot log file into test report by @MikeSchulze in #164
  • GD-156: Install Godot exception handler and forward uncaught exceptions as test failure. by @MikeSchulze in #162
  • GD-682: Rework on GdUnit4Net API Godot bridge by @MikeSchulze in #197
  • GD-27: Add VSTest filter support with test categories and traits by @MikeSchulze in #201
  • GD-240: Add GDUNIT4NET_API_V5 Conditional Compilation Constant by @MikeSchulze in #241
  • Upgrade to .NET 8/9 with C# 12 support by @MikeSchulze in #267
  • GD-211: Implement missing AwaitSignalOn by @MikeSchulze in #282

🪲 Bug Fixes

  • GD-149: Add error to the execution log when the test session timeout occurs by @MikeSchulze in #150
  • GD-152: Fix test case display name for dynamic test data driven tests by @MikeSchulze in #176
  • Fixes Godot exception monitoring issues by @MikeSchulze in #187
  • Make WithTimeout public by @MikeSchulze in #189
  • GD-199: TestRunner install ends with abnormal exit on large projects by @MikeSchulze in #200
  • GD-203: Handle failure reporting for test stages [Before] and [After] by @MikeSchulze in #204
  • GD-212: Fix vector assertion IsEqualApprox by @MikeSchulze in #214
  • GD-284: Fix test failure causes the entire test execution if it is executed in the Godot Editor by @MikeSchulze in #285

🧹 Maintenance

🔄 CI/CD

New Contributors

Full Changelog: v4.3.1...v5.0.0