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
22 changes: 22 additions & 0 deletions TUnit.Engine.Tests/GitHubReporterTests.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using Microsoft.Testing.Platform.Extensions.Messages;
using Microsoft.Testing.Platform.TestHost;
using Shouldly;
using TUnit.Engine.Exceptions;
using TUnit.Engine.Reporters;

namespace TUnit.Engine.Tests;
Expand Down Expand Up @@ -260,6 +261,27 @@ await FeedTestMessages(reporter,
output.ShouldContain("Timeout");
}

[Test]
public async Task AfterRunAsync_Unwraps_TestFailedException_For_Grouping()
{
var (reporter, outputFile) = await SetupReporter();

var inner1 = new InvalidOperationException("Docker image not created");
var inner2 = new InvalidOperationException("Docker image not created");
await FeedTestMessages(reporter,
CreateFailedTestMessage("1", "T1", "Svc", new TestFailedException(inner1)),
CreateFailedTestMessage("2", "T2", "Svc", new TestFailedException(inner2))
);

await reporter.AfterRunAsync(1, CancellationToken.None);

var output = await File.ReadAllTextAsync(outputFile);
output.ShouldContain("InvalidOperationException (2 tests)");
output.ShouldNotContain("TestFailedException (");
output.ShouldContain("Docker image not created");
output.ShouldContain("2 × `InvalidOperationException`");
}

[Test]
public async Task AfterRunAsync_Other_NonPassing_Tests_Remain_Separate()
{
Expand Down
16 changes: 15 additions & 1 deletion TUnit.Engine/Exceptions/TUnitFailedException.cs
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
using TUnit.Core.Exceptions;
using System.Diagnostics.CodeAnalysis;
using TUnit.Core.Exceptions;
using TUnit.Core.Helpers;
using TUnit.Engine.CommandLineProviders;

namespace TUnit.Engine.Exceptions;

public abstract class TUnitFailedException : TUnitException
{
public Exception? WrappedException { get; }

protected TUnitFailedException(Exception exception) : base($"{exception.GetType().Name}: {exception.Message}", exception.InnerException)
{
WrappedException = exception;
StackTrace = FilterStackTrace(exception.StackTrace);
}

Expand All @@ -18,6 +22,16 @@ protected TUnitFailedException(string? message, Exception? innerException) : bas

public override string StackTrace { get; }

[return: NotNullIfNotNull(nameof(exception))]
public static Exception? Unwrap(Exception? exception)
{
while (exception is TUnitFailedException { WrappedException: { } wrapped })
{
exception = wrapped;
}
return exception;
}

// The hint only mentions --detailed-stacktrace because filtering is bypassed
// entirely when --log-level Debug/Trace is set (see TUnitMessageBus.SimplifyStacktrace),
// so users on debug logging will never see this message.
Expand Down
9 changes: 5 additions & 4 deletions TUnit.Engine/Reporters/GitHubReporter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
using Microsoft.Testing.Platform.Extensions.TestHost;
using TUnit.Engine.Configuration;
using TUnit.Engine.Constants;
using TUnit.Engine.Exceptions;
using TUnit.Engine.Framework;
using TUnit.Engine.Helpers;

Expand Down Expand Up @@ -528,9 +529,9 @@ or TimeoutTestNodeStateProperty
return stateProperty switch
{
FailedTestNodeStateProperty failedTestNodeStateProperty =>
GetTruncatedExceptionMessage(failedTestNodeStateProperty.Exception) ?? "Test failed",
GetTruncatedExceptionMessage(TUnitFailedException.Unwrap(failedTestNodeStateProperty.Exception)) ?? "Test failed",
ErrorTestNodeStateProperty errorTestNodeStateProperty =>
GetTruncatedExceptionMessage(errorTestNodeStateProperty.Exception) ?? "Test failed",
GetTruncatedExceptionMessage(TUnitFailedException.Unwrap(errorTestNodeStateProperty.Exception)) ?? "Test failed",
TimeoutTestNodeStateProperty timeoutTestNodeStateProperty => timeoutTestNodeStateProperty.Explanation,
#pragma warning disable CS0618 // CancelledTestNodeStateProperty is obsolete
CancelledTestNodeStateProperty => "Test was cancelled",
Expand Down Expand Up @@ -637,8 +638,8 @@ internal void SetReporterStyle(GitHubReporterStyle style)

private static string GetExceptionTypeName(IProperty? stateProperty) => stateProperty switch
{
FailedTestNodeStateProperty f => f.Exception?.GetType().Name ?? "Unknown",
ErrorTestNodeStateProperty e => e.Exception?.GetType().Name ?? "Unknown",
FailedTestNodeStateProperty f => TUnitFailedException.Unwrap(f.Exception)?.GetType().Name ?? "Unknown",
ErrorTestNodeStateProperty e => TUnitFailedException.Unwrap(e.Exception)?.GetType().Name ?? "Unknown",
TimeoutTestNodeStateProperty => "Timeout",
_ => "Unknown"
};
Expand Down
3 changes: 3 additions & 0 deletions TUnit.Engine/Reporters/Html/HtmlReporter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
using TUnit.Core;
using TUnit.Engine.Configuration;
using TUnit.Engine.Constants;
using TUnit.Engine.Exceptions;
using TUnit.Engine.Framework;

#pragma warning disable TPEXP
Expand Down Expand Up @@ -593,6 +594,8 @@ private static (string Status, ReportExceptionData? Exception, string? SkipReaso
return null;
}

ex = TUnitFailedException.Unwrap(ex);

return new ReportExceptionData
{
Type = ex.GetType().FullName ?? ex.GetType().Name,
Expand Down
5 changes: 3 additions & 2 deletions TUnit.Engine/Xml/JUnitXmlWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System.Text;
using System.Xml;
using Microsoft.Testing.Platform.Extensions.Messages;
using TUnit.Engine.Exceptions;

namespace TUnit.Engine.Xml;

Expand Down Expand Up @@ -245,7 +246,7 @@ private static void WriteFailure(XmlWriter writer, FailedTestNodeStateProperty f
{
writer.WriteStartElement("failure");

var exception = failed.Exception;
var exception = TUnitFailedException.Unwrap(failed.Exception);
if (exception != null)
{
writer.WriteAttributeString("message", SanitizeForXml(exception.Message));
Expand All @@ -267,7 +268,7 @@ private static void WriteError(XmlWriter writer, ErrorTestNodeStateProperty erro
{
writer.WriteStartElement("error");

var exception = error.Exception;
var exception = TUnitFailedException.Unwrap(error.Exception);
if (exception != null)
{
writer.WriteAttributeString("message", SanitizeForXml(exception.Message));
Expand Down
Loading