Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions TUnit.Engine.Tests/DataSourceExceptionPropagationTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,4 +53,27 @@ await RunTestsWithFilter(
}
]);
}

[Test]
public async Task NestedClassDataSource_ConstructorThrows_FailsTestWithException()
{
await RunTestsWithFilter(
"/*/*/NestedDataSourcesThrow/*",
[
result => result.ResultSummary.Outcome.ShouldBe("Failed"),
result => result.ResultSummary.Counters.Total.ShouldBe(1),
result => result.ResultSummary.Counters.Passed.ShouldBe(0),
result => result.ResultSummary.Counters.Failed.ShouldBe(1),
result =>
{
var errorMessage = result.Results.First().Output?.ErrorInfo?.Message;
errorMessage.ShouldNotBeNull("Expected an error message");
// Should contain the original exception message from the DataSource3 constructor
errorMessage.ShouldContain("Oops something went wrong");
// Should indicate the nested property injection failure path
errorMessage.ShouldContain("Failed to inject properties for type 'DataSource'");
errorMessage.ShouldContain("Failed to inject properties for type 'DataSource2'");
}
]);
}
}
11 changes: 11 additions & 0 deletions TUnit.Engine/Services/TestExecution/TestCoordinator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,17 @@ private async ValueTask ExecuteTestInternalAsync(AbstractExecutableTest test, Ca

_contextRestorer.RestoreContext(test);

// Check if test was already marked as failed during registration (e.g., property injection failure)
// If so, skip execution and report the failure immediately
var existingResult = test.Context.Execution.Result;
if (existingResult?.State == TestState.Failed)
{
var exception = existingResult.Exception ?? new InvalidOperationException("Test failed during registration");
await _stateManager.MarkFailedAsync(test, exception).ConfigureAwait(false);
await _eventReceiverOrchestrator.InvokeTestEndEventReceiversAsync(test.Context, cancellationToken).ConfigureAwait(false);
return;
}

// Clear Result and timing from any previous execution (important for repeated tests)
test.Context.Execution.Result = null;
test.Context.TestStart = null;
Expand Down
61 changes: 61 additions & 0 deletions TUnit.TestProject/NestedDataSourcesThrow.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
using TUnit.Core.Interfaces;

namespace TUnit.TestProject;

public class NestedDataSourcesThrow
{
[ClassDataSource]
public DataSource Data { get; set; } = null!;

[Test]
public Task Test1()
{
// This test body should never execute - the test should fail during property injection
// with "Oops something went wrong" from DataSource3's constructor
Assert.Fail("Test body should not have executed - expected property injection to fail with 'Oops something went wrong'");
return Task.CompletedTask;
}

public class DataSource : IAsyncInitializer
{
[ClassDataSource]
public DataSource2 DataSource2 { get; set; } = null!;

public bool IsInitialized { get; set; }

public Task InitializeAsync()
{
IsInitialized = true;
return Task.CompletedTask;
}
}

public class DataSource2 : IAsyncInitializer
{
[ClassDataSource]
public DataSource3 DataSource3 { get; set; } = null!;

public bool IsInitialized { get; set; }

public Task InitializeAsync()
{
IsInitialized = true;
return Task.CompletedTask;
}
}

public class DataSource3 : IAsyncInitializer
{
public DataSource3()
{
throw new Exception("Oops something went wrong");
}
public bool IsInitialized { get; set; }

public Task InitializeAsync()
{
IsInitialized = true;
return Task.CompletedTask;
}
}
}
Loading