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
5 changes: 1 addition & 4 deletions TUnit.Engine/Services/TestExecution/TestCoordinator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -146,13 +146,10 @@ await RetryHelper.ExecuteWithRetry(test.Context, async () =>
}
catch (SkipTestException ex)
{
test.Context.SkipReason = ex.Message;
await _stateManager.MarkSkippedAsync(test, ex.Message);

// Invoke skipped event receivers
await _eventReceiverOrchestrator.InvokeTestSkippedEventReceiversAsync(test.Context, cancellationToken);

// Invoke test end event receivers for skipped tests
await _eventReceiverOrchestrator.InvokeTestEndEventReceiversAsync(test.Context, cancellationToken);
}
catch (Exception ex)
{
Expand Down
64 changes: 64 additions & 0 deletions TUnit.TestProject/LastTestEventReceiverTests.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using TUnit.Core;
using TUnit.Core.Interfaces;

namespace TUnit.TestProject;
Expand Down Expand Up @@ -163,3 +164,66 @@ public ValueTask OnTestEnd(TestContext context)
return default;
}
}

// Test for runtime skip using Skip.Test()
public class RuntimeSkipEventReceiverTests
{
public static readonly List<string> Events = [];
public static string? CapturedSkipReason = null;

[Before(Test)]
public void ClearEvents()
{
Events.Clear();
CapturedSkipReason = null;
}

[Test]
[RuntimeSkipEventReceiverAttribute]
public void RuntimeSkippedTestWithCustomReason()
{
Skip.Test("Custom runtime skip reason");
}

[After(Test)]
public async Task VerifyRuntimeSkipEventFired(TestContext context)
{
// Give some time for async event receivers to complete
await Task.Delay(100);

if (context.GetDisplayName().Contains("RuntimeSkippedTestWithCustomReason"))
{
// Verify skip reason is preserved
await Assert.That(CapturedSkipReason).IsEqualTo("Custom runtime skip reason");

// Verify both skipped and end events are fired
await Assert.That(Events).Contains("TestSkipped");
await Assert.That(Events).Contains("TestEnd");

// Verify TestEnd is called exactly once (not twice)
var testEndCount = Events.Count(e => e == "TestEnd");
await Assert.That(testEndCount).IsEqualTo(1);
}
}
}

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = false)]
public class RuntimeSkipEventReceiverAttribute : Attribute,
ITestSkippedEventReceiver,
ITestEndEventReceiver
{
public int Order => 0;

public ValueTask OnTestSkipped(TestContext context)
{
RuntimeSkipEventReceiverTests.Events.Add("TestSkipped");
RuntimeSkipEventReceiverTests.CapturedSkipReason = context.SkipReason;
return default;
}

public ValueTask OnTestEnd(TestContext context)
{
RuntimeSkipEventReceiverTests.Events.Add("TestEnd");
return default;
}
}
Loading