From 67fa1bb4a4c4f73d3cad82df50605fa42333e9df Mon Sep 17 00:00:00 2001 From: Copilot <223556219+Copilot@users.noreply.github.com> Date: Sat, 16 May 2026 18:39:51 +0200 Subject: [PATCH 1/8] Apply structured assertion messages (RFC 012) to Assert.Fail / Assert.Inconclusive Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../TestFramework/Assertions/Assert.Fail.cs | 5 +- .../Assertions/Assert.Inconclusive.cs | 10 +++- .../Resources/FrameworkMessages.resx | 3 + .../Resources/xlf/FrameworkMessages.cs.xlf | 5 ++ .../Resources/xlf/FrameworkMessages.de.xlf | 5 ++ .../Resources/xlf/FrameworkMessages.es.xlf | 5 ++ .../Resources/xlf/FrameworkMessages.fr.xlf | 5 ++ .../Resources/xlf/FrameworkMessages.it.xlf | 5 ++ .../Resources/xlf/FrameworkMessages.ja.xlf | 5 ++ .../Resources/xlf/FrameworkMessages.ko.xlf | 5 ++ .../Resources/xlf/FrameworkMessages.pl.xlf | 5 ++ .../Resources/xlf/FrameworkMessages.pt-BR.xlf | 5 ++ .../Resources/xlf/FrameworkMessages.ru.xlf | 5 ++ .../Resources/xlf/FrameworkMessages.tr.xlf | 5 ++ .../xlf/FrameworkMessages.zh-Hans.xlf | 5 ++ .../xlf/FrameworkMessages.zh-Hant.xlf | 5 ++ .../RetryTests.cs | 2 +- .../Execution/TestAssemblyInfoTests.cs | 8 +-- .../Execution/TestClassInfoTests.cs | 8 +-- .../Execution/TestExecutionManagerTests.cs | 2 +- .../Execution/TestMethodInfoTests.cs | 10 ++-- .../AssertTests.FailInconclusive.cs | 56 +++++++++++++++++++ .../AssertTests.InconclusiveTests.cs | 2 +- .../Assertions/AssertTests.ScopeTests.cs | 6 +- 24 files changed, 157 insertions(+), 20 deletions(-) create mode 100644 test/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.FailInconclusive.cs diff --git a/src/TestFramework/TestFramework/Assertions/Assert.Fail.cs b/src/TestFramework/TestFramework/Assertions/Assert.Fail.cs index e377044d5a..b5558784f3 100644 --- a/src/TestFramework/TestFramework/Assertions/Assert.Fail.cs +++ b/src/TestFramework/TestFramework/Assertions/Assert.Fail.cs @@ -24,6 +24,9 @@ public sealed partial class Assert public static void Fail(string message = "") { TelemetryCollector.TrackAssertionCall("Assert.Fail"); - ThrowAssertFailed("Assert.Fail", BuildUserMessage(message)); + + StructuredAssertionMessage structured = new(string.Empty); + structured.WithUserMessage(message); + ThrowAssertFailed(structured); } } diff --git a/src/TestFramework/TestFramework/Assertions/Assert.Inconclusive.cs b/src/TestFramework/TestFramework/Assertions/Assert.Inconclusive.cs index ecd743b0c9..65d79b4ab5 100644 --- a/src/TestFramework/TestFramework/Assertions/Assert.Inconclusive.cs +++ b/src/TestFramework/TestFramework/Assertions/Assert.Inconclusive.cs @@ -26,7 +26,13 @@ public static void Inconclusive(string message = "") TelemetryCollector.TrackAssertionCall("Assert.Inconclusive"); string userMessage = BuildUserMessage(message); - throw new AssertInconclusiveException( - FormatAssertionFailed("Assert.Inconclusive", userMessage)); + throw new AssertInconclusiveException(FormatInconclusive(userMessage)); } + + private static string FormatInconclusive(string? message) + => string.IsNullOrWhiteSpace(message) + ? FrameworkMessages.InconclusivePrefix + : message![0] is '\n' or '\r' + ? string.Concat(FrameworkMessages.InconclusivePrefix, message) + : $"{FrameworkMessages.InconclusivePrefix} {message}"; } diff --git a/src/TestFramework/TestFramework/Resources/FrameworkMessages.resx b/src/TestFramework/TestFramework/Resources/FrameworkMessages.resx index 4c06871944..cca6a902a6 100644 --- a/src/TestFramework/TestFramework/Resources/FrameworkMessages.resx +++ b/src/TestFramework/TestFramework/Resources/FrameworkMessages.resx @@ -289,6 +289,9 @@ Actual: {2} {0} failed. + + Assert.Inconclusive. + {0} Expected type:<{1}>. Actual type:<{2}>. diff --git a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.cs.xlf b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.cs.xlf index b2828f2192..494ef0b370 100644 --- a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.cs.xlf +++ b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.cs.xlf @@ -442,6 +442,11 @@ Skutečnost: {2} Očekávala se kolekce {1} velikosti. Skutečnost: {2} {0} + + Assert.Inconclusive. + Assert.Inconclusive. + + The property 'TestContext.{0}' is related to current test is not available during assembly or class fixtures. Vlastnost TestContext.{0} souvisí s aktuálním testem a není k dispozici během sestavení nebo používání testovacích přípravků tříd. diff --git a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.de.xlf b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.de.xlf index 3b0497e62d..d75d6880b9 100644 --- a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.de.xlf +++ b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.de.xlf @@ -442,6 +442,11 @@ Tatsächlich: {2} Es wurde eine Sammlung mit einer Größe {1} erwartet. Tatsächlich: {2}. {0} + + Assert.Inconclusive. + Assert.Inconclusive. + + The property 'TestContext.{0}' is related to current test is not available during assembly or class fixtures. Die Eigenschaft „TestContext.{0}“ im Zusammenhang mit dem aktuellen Test steht während Assembly- oder Klassenfixierungen nicht zur Verfügung. diff --git a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.es.xlf b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.es.xlf index f6180a742f..3676037ee7 100644 --- a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.es.xlf +++ b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.es.xlf @@ -442,6 +442,11 @@ Real: {2} Se esperaba una colección de tamaño {1}. Real: {2}. {0} + + Assert.Inconclusive. + Assert.Inconclusive. + + The property 'TestContext.{0}' is related to current test is not available during assembly or class fixtures. La propiedad "TestContext.{0}" está relacionado con la prueba actual y no está disponible durante los accesorios de ensamblado o clase. diff --git a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.fr.xlf b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.fr.xlf index 21e859b0b8..0faed641e3 100644 --- a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.fr.xlf +++ b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.fr.xlf @@ -442,6 +442,11 @@ Réel : {2} Collection de tailles attendue {1}. Réel : {2}. {0} + + Assert.Inconclusive. + Assert.Inconclusive. + + The property 'TestContext.{0}' is related to current test is not available during assembly or class fixtures. La propriété « TestContext.{0} », liée au test en cours, n’est pas disponible pendant les fixtures d’assembly ou de classe. diff --git a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.it.xlf b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.it.xlf index 6d2040c828..f0173929f3 100644 --- a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.it.xlf +++ b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.it.xlf @@ -442,6 +442,11 @@ Effettivo: {2} Prevista raccolta di dimensioni {1}. Effettivo: {2}. {0} + + Assert.Inconclusive. + Assert.Inconclusive. + + The property 'TestContext.{0}' is related to current test is not available during assembly or class fixtures. La proprietà 'TestContext.{0}' relativa al test corrente non è disponibile durante le fixture di assembly o classe. diff --git a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.ja.xlf b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.ja.xlf index 392fa6ef72..de3ba8d95b 100644 --- a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.ja.xlf +++ b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.ja.xlf @@ -442,6 +442,11 @@ Actual: {2} サイズ {1} のコレクションが必要です。実際: {2}。{0} + + Assert.Inconclusive. + Assert.Inconclusive. + + The property 'TestContext.{0}' is related to current test is not available during assembly or class fixtures. プロパティ 'TestContext.{0}' は現在のテストに関連しており、アセンブリまたはクラス フィクスチャの間は使用できません。 diff --git a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.ko.xlf b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.ko.xlf index caed5cd6c5..ff7817e6cc 100644 --- a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.ko.xlf +++ b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.ko.xlf @@ -442,6 +442,11 @@ Actual: {2} {1} 크기 컬렉션이 필요합니다. 실제: {2}. {0} + + Assert.Inconclusive. + Assert.Inconclusive. + + The property 'TestContext.{0}' is related to current test is not available during assembly or class fixtures. 현재 테스트와 관련된 'TestContext.{0}' 속성은 어셈블리나 클래스 픽스처 실행 중에는 사용할 수 없습니다. diff --git a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.pl.xlf b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.pl.xlf index 5da692e8b6..fb82ee88fa 100644 --- a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.pl.xlf +++ b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.pl.xlf @@ -442,6 +442,11 @@ Rzeczywiste: {2} Oczekiwano kolekcji rozmiaru {1}. Wartość rzeczywista: {2}. {0} + + Assert.Inconclusive. + Assert.Inconclusive. + + The property 'TestContext.{0}' is related to current test is not available during assembly or class fixtures. Właściwość „TestContext.{0}” jest powiązana z bieżącym testem i nie jest dostępna podczas montażu lub konfiguracji klasy. diff --git a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.pt-BR.xlf b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.pt-BR.xlf index 935e661ad4..0aabcd371f 100644 --- a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.pt-BR.xlf +++ b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.pt-BR.xlf @@ -442,6 +442,11 @@ Real: {2} Coleção esperada de tamanho {1}. Real: {2}. {0} + + Assert.Inconclusive. + Assert.Inconclusive. + + The property 'TestContext.{0}' is related to current test is not available during assembly or class fixtures. A propriedade "TestContext.{0}" está relacionada ao teste atual não está disponível durante os acessórios de assembly ou classe. diff --git a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.ru.xlf b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.ru.xlf index 310e5898df..54f52b0998 100644 --- a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.ru.xlf +++ b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.ru.xlf @@ -442,6 +442,11 @@ Actual: {2} Ожидается коллекция размеров {1}. Фактически: {2}. {0} + + Assert.Inconclusive. + Assert.Inconclusive. + + The property 'TestContext.{0}' is related to current test is not available during assembly or class fixtures. Свойство "TestContext.{0}" связано с текущим тестом и недоступно во время выполнения средств тестирования сборок или классов. diff --git a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.tr.xlf b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.tr.xlf index 5bb57205a5..a88a1c8356 100644 --- a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.tr.xlf +++ b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.tr.xlf @@ -442,6 +442,11 @@ Gerçekte olan: {2} Beklenen boyut {1}. Gerçek: {2}. {0} + + Assert.Inconclusive. + Assert.Inconclusive. + + The property 'TestContext.{0}' is related to current test is not available during assembly or class fixtures. 'TestContext.{0}' özelliği, derleme veya sınıf sabitlemeleri sırasında mevcut testle ilişkili değildir. diff --git a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.zh-Hans.xlf b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.zh-Hans.xlf index 6fa3cb17f3..eec7bdabd1 100644 --- a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.zh-Hans.xlf +++ b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.zh-Hans.xlf @@ -442,6 +442,11 @@ Actual: {2} 大小 {1} 的预期集合。实际: {2}。{0} + + Assert.Inconclusive. + Assert.Inconclusive. + + The property 'TestContext.{0}' is related to current test is not available during assembly or class fixtures. 属性‘TestContext.{0}’与当前测试相关,在程序集或类固定例程期间不可用。 diff --git a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.zh-Hant.xlf b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.zh-Hant.xlf index 366ab94673..b1f6004156 100644 --- a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.zh-Hant.xlf +++ b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.zh-Hant.xlf @@ -442,6 +442,11 @@ Actual: {2} 預期的大小集合 {1}。實際: {2}。{0} + + Assert.Inconclusive. + Assert.Inconclusive. + + The property 'TestContext.{0}' is related to current test is not available during assembly or class fixtures. 屬性 'TestContext.{0}' 與目前測試相關,無法在組件或類別測試夾具期間使用。 diff --git a/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/RetryTests.cs b/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/RetryTests.cs index 4d8ff10a08..bcaf20e488 100644 --- a/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/RetryTests.cs +++ b/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/RetryTests.cs @@ -26,7 +26,7 @@ TestMethod5 executed 4 times. """); testHostResult.AssertOutputContains("failed TestMethod5"); - testHostResult.AssertOutputContains("Assert.Fail failed. Failing TestMethod4. Attempts: 4 (from TestContext: 4)"); + testHostResult.AssertOutputContains("Assertion failed.\r\nFailing TestMethod4. Attempts: 4 (from TestContext: 4)"); testHostResult.AssertOutputContainsSummary(failed: 1, passed: 4, skipped: 0); } diff --git a/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/TestAssemblyInfoTests.cs b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/TestAssemblyInfoTests.cs index fe081e28cd..8450abb090 100644 --- a/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/TestAssemblyInfoTests.cs +++ b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/TestAssemblyInfoTests.cs @@ -146,7 +146,7 @@ public async Task RunAssemblyInitializeShouldThrowTestFailedExceptionOnAssertion var exception = (await _testAssemblyInfo.RunAssemblyInitializeAsync(_testContext)).TestFailureException as TestFailedException; exception.Should().NotBeNull(); exception.Outcome.Should().Be(UnitTestOutcome.Failed); - exception.Message.Should().Be("Assembly Initialization method Microsoft.VisualStudio.TestPlatform.MSTestAdapter.UnitTests.Execution.TestAssemblyInfoTests+DummyTestClass.AssemblyInitializeMethod threw exception. Microsoft.VisualStudio.TestTools.UnitTesting.AssertFailedException: Assert.Fail failed. Test failure. Aborting test execution."); + exception.Message.Should().Be("Assembly Initialization method Microsoft.VisualStudio.TestPlatform.MSTestAdapter.UnitTests.Execution.TestAssemblyInfoTests+DummyTestClass.AssemblyInitializeMethod threw exception. Microsoft.VisualStudio.TestTools.UnitTesting.AssertFailedException: Assertion failed.\r\nTest failure. Aborting test execution."); exception.StackTraceInformation!.ErrorStackTrace.Should().Contain( "Microsoft.VisualStudio.TestPlatform.MSTestAdapter.UnitTests.Execution.TestAssemblyInfoTests.DummyTestClass.AssemblyInitializeMethod"); exception.InnerException.Should().BeOfType(); @@ -162,7 +162,7 @@ public async Task RunAssemblyInitializeShouldThrowTestFailedExceptionWithInconcl var exception = (await _testAssemblyInfo.RunAssemblyInitializeAsync(_testContext)).TestFailureException as TestFailedException; exception.Should().NotBeNull(); exception.Outcome.Should().Be(UnitTestOutcome.Inconclusive); - exception.Message.Should().Be("Assembly Initialization method Microsoft.VisualStudio.TestPlatform.MSTestAdapter.UnitTests.Execution.TestAssemblyInfoTests+DummyTestClass.AssemblyInitializeMethod threw exception. Microsoft.VisualStudio.TestTools.UnitTesting.AssertInconclusiveException: Assert.Inconclusive failed. Test Inconclusive. Aborting test execution."); + exception.Message.Should().Be("Assembly Initialization method Microsoft.VisualStudio.TestPlatform.MSTestAdapter.UnitTests.Execution.TestAssemblyInfoTests+DummyTestClass.AssemblyInitializeMethod threw exception. Microsoft.VisualStudio.TestTools.UnitTesting.AssertInconclusiveException: Assert.Inconclusive. Test Inconclusive. Aborting test execution."); exception.StackTraceInformation!.ErrorStackTrace.Should().Contain( "Microsoft.VisualStudio.TestPlatform.MSTestAdapter.UnitTests.Execution.TestAssemblyInfoTests.DummyTestClass.AssemblyInitializeMethod"); exception.InnerException.Should().BeOfType(); @@ -264,7 +264,7 @@ public async Task RunAssemblyCleanupShouldReturnAssertFailureExceptionDetails() _testAssemblyInfo.AssemblyCleanupMethod = typeof(DummyTestClass).GetMethod("AssemblyCleanupMethod")!; string? actualErrorMessage = (await _testAssemblyInfo.ExecuteAssemblyCleanupAsync(GetTestContext()))?.Message; actualErrorMessage!.StartsWith( - "Assembly Cleanup method DummyTestClass.AssemblyCleanupMethod failed. Error Message: Assert.Fail failed. Test Failure..", StringComparison.Ordinal).Should().BeTrue($"Value: {actualErrorMessage}"); + "Assembly Cleanup method DummyTestClass.AssemblyCleanupMethod failed. Error Message: Assertion failed.\r\nTest Failure..", StringComparison.Ordinal).Should().BeTrue($"Value: {actualErrorMessage}"); } public async Task RunAssemblyCleanupShouldReturnAssertInconclusiveExceptionDetails() @@ -276,7 +276,7 @@ public async Task RunAssemblyCleanupShouldReturnAssertInconclusiveExceptionDetai _testAssemblyInfo.AssemblyCleanupMethod = typeof(DummyTestClass).GetMethod("AssemblyCleanupMethod")!; string? actualErrorMessage = (await _testAssemblyInfo.ExecuteAssemblyCleanupAsync(GetTestContext()))?.Message; actualErrorMessage!.StartsWith( - "Assembly Cleanup method DummyTestClass.AssemblyCleanupMethod failed. Error Message: Assert.Inconclusive failed. Test Inconclusive..", StringComparison.Ordinal).Should().BeTrue($"Value: {actualErrorMessage}"); + "Assembly Cleanup method DummyTestClass.AssemblyCleanupMethod failed. Error Message: Assert.Inconclusive. Test Inconclusive..", StringComparison.Ordinal).Should().BeTrue($"Value: {actualErrorMessage}"); } public async Task RunAssemblyCleanupShouldReturnExceptionDetailsOfNonAssertExceptions() diff --git a/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/TestClassInfoTests.cs b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/TestClassInfoTests.cs index 1db8a177bc..d131c9b542 100644 --- a/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/TestClassInfoTests.cs +++ b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/TestClassInfoTests.cs @@ -350,7 +350,7 @@ public void RunClassInitializeShouldThrowTestFailedExceptionOnAssertionFailure() exception.Should().NotBeNull(); exception.Outcome.Should().Be(UnitTestOutcome.Failed); - exception.Message.Should().Be("Class Initialization method Microsoft.VisualStudio.TestPlatform.MSTestAdapter.UnitTests.Execution.TestClassInfoTests+DummyTestClass.ClassInitializeMethod threw exception. Microsoft.VisualStudio.TestTools.UnitTesting.AssertFailedException: Assert.Fail failed. Test failure."); + exception.Message.Should().Be("Class Initialization method Microsoft.VisualStudio.TestPlatform.MSTestAdapter.UnitTests.Execution.TestClassInfoTests+DummyTestClass.ClassInitializeMethod threw exception. Microsoft.VisualStudio.TestTools.UnitTesting.AssertFailedException: Assertion failed.\r\nTest failure."); exception.StackTraceInformation!.ErrorStackTrace.Contains( "Microsoft.VisualStudio.TestPlatform.MSTestAdapter.UnitTests.Execution.TestClassInfoTests.DummyTestClass.ClassInitializeMethod", StringComparison.Ordinal).Should().BeTrue(); exception.InnerException.Should().BeOfType(); @@ -367,7 +367,7 @@ public void RunClassInitializeShouldThrowTestFailedExceptionWithInconclusiveOnAs exception.Should().NotBeNull(); exception.Outcome.Should().Be(UnitTestOutcome.Inconclusive); - exception.Message.Should().Be("Class Initialization method Microsoft.VisualStudio.TestPlatform.MSTestAdapter.UnitTests.Execution.TestClassInfoTests+DummyTestClass.ClassInitializeMethod threw exception. Microsoft.VisualStudio.TestTools.UnitTesting.AssertInconclusiveException: Assert.Inconclusive failed. Test Inconclusive."); + exception.Message.Should().Be("Class Initialization method Microsoft.VisualStudio.TestPlatform.MSTestAdapter.UnitTests.Execution.TestClassInfoTests+DummyTestClass.ClassInitializeMethod threw exception. Microsoft.VisualStudio.TestTools.UnitTesting.AssertInconclusiveException: Assert.Inconclusive. Test Inconclusive."); exception.StackTraceInformation!.ErrorStackTrace.Contains( "Microsoft.VisualStudio.TestPlatform.MSTestAdapter.UnitTests.Execution.TestClassInfoTests.DummyTestClass.ClassInitializeMethod", StringComparison.Ordinal).Should().BeTrue(); exception.InnerException.Should().BeOfType(); @@ -481,7 +481,7 @@ public async Task RunClassCleanupShouldReturnAssertFailureExceptionDetails() // Assert classCleanupException.Should().NotBeNull(); classCleanupException.Message.StartsWith("Class Cleanup method DummyTestClass.ClassCleanupMethod failed.", StringComparison.Ordinal).Should().BeTrue(); - classCleanupException.Message.Contains("Error Message: Assert.Fail failed. Test Failure.").Should().BeTrue(); + classCleanupException.Message.Contains("Error Message: Assertion failed.\r\nTest Failure.").Should().BeTrue(); classCleanupException.Message.Should().Contain( $"{typeof(TestClassInfoTests).FullName}.DummyTestClass.ClassCleanupMethod", $"Value: {classCleanupException.Message}"); @@ -502,7 +502,7 @@ public async Task RunClassCleanupShouldReturnAssertInconclusiveExceptionDetails( // Assert classCleanupException.Should().NotBeNull(); classCleanupException.Message.StartsWith("Class Cleanup method DummyTestClass.ClassCleanupMethod failed.", StringComparison.Ordinal).Should().BeTrue(); - classCleanupException.Message.Contains("Error Message: Assert.Inconclusive failed. Test Inconclusive.").Should().BeTrue(); + classCleanupException.Message.Contains("Error Message: Assert.Inconclusive. Test Inconclusive.").Should().BeTrue(); classCleanupException.Message.Should().Contain( $"{typeof(TestClassInfoTests).FullName}.DummyTestClass.ClassCleanupMethod", $"Value: {classCleanupException.Message}"); diff --git a/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/TestExecutionManagerTests.cs b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/TestExecutionManagerTests.cs index e9ead72c13..59608bc623 100644 --- a/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/TestExecutionManagerTests.cs +++ b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/TestExecutionManagerTests.cs @@ -159,7 +159,7 @@ public async Task RunTestsForMultipleTestShouldSendMultipleResults() List expectedTestCaseStartList = ["PassingTest", "FailingTest"]; List expectedTestCaseEndList = ["PassingTest:Passed", "FailingTest:Failed"]; - List expectedResultList = ["PassingTest Passed", "FailingTest Failed\r\n Message: Assert.Fail failed."]; + List expectedResultList = ["PassingTest Passed", "FailingTest Failed\r\n Message: Assertion failed."]; expectedTestCaseStartList.SequenceEqual(_frameworkHandle.TestCaseStartList).Should().BeTrue(); expectedTestCaseEndList.SequenceEqual(_frameworkHandle.TestCaseEndList).Should().BeTrue(); diff --git a/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/TestMethodInfoTests.cs b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/TestMethodInfoTests.cs index e4ed2fa1a8..8335a860c7 100644 --- a/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/TestMethodInfoTests.cs +++ b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/TestMethodInfoTests.cs @@ -863,7 +863,7 @@ public async Task TestMethodInfoInvokeWhenTestThrowsAssertFailReturnsExpectedRes Resource.UTA_InitMethodThrows, typeof(DummyTestClass).FullName, _testClassInfo.TestInitializeMethod!.Name, - "Assert.Fail failed. dummyFailMessage"); + "Assertion failed.\r\ndummyFailMessage"); var testMethodInfo = new TestMethodInfo(_methodInfo, _testClassInfo) { @@ -898,7 +898,7 @@ public async Task TestMethodInfoInvokeWhenTestThrowsAssertInconclusiveReturnsExp Resource.UTA_InitMethodThrows, typeof(DummyTestClass).FullName, _testClassInfo.TestInitializeMethod!.Name, - "Assert.Inconclusive failed. dummyFailMessage"); + "Assert.Inconclusive. dummyFailMessage"); var testMethodInfo = new TestMethodInfo(_methodInfo, _testClassInfo) { @@ -942,7 +942,7 @@ public async Task TestMethodInfoInvokeWhenConstructorThrowsAssertInconclusiveRet var exception = result.TestFailureException as TestFailedException; exception.Should().NotBeNull(); - exception.Message.Should().Be("Assert.Inconclusive failed. dummyInconclusiveMessage"); + exception.Message.Should().Be("Assert.Inconclusive. dummyInconclusiveMessage"); exception.Outcome.Should().Be(UnitTestOutcome.Inconclusive); exception.InnerException.Should().BeOfType(); #if DEBUG @@ -1110,7 +1110,7 @@ public async Task TestMethodInfoInvokeWhenTestCleanupThrowsAssertInconclusiveRet Resource.UTA_CleanupMethodThrows, typeof(DummyTestClass).FullName, _testClassInfo.TestCleanupMethod.Name, - "Microsoft.VisualStudio.TestTools.UnitTesting.AssertInconclusiveException: Assert.Inconclusive failed. Test inconclusive"); + "Microsoft.VisualStudio.TestTools.UnitTesting.AssertInconclusiveException: Assert.Inconclusive. Test inconclusive"); TestResult result = await _testMethodInfo.InvokeAsync(null); @@ -1137,7 +1137,7 @@ public async Task TestMethodInfoInvokeWhenTestCleanupThrowsAssertFailedReturnsEx Resource.UTA_CleanupMethodThrows, typeof(DummyTestClass).FullName, _testClassInfo.TestCleanupMethod!.Name, - "Microsoft.VisualStudio.TestTools.UnitTesting.AssertFailedException: Assert.Fail failed. Test failed"); + "Microsoft.VisualStudio.TestTools.UnitTesting.AssertFailedException: Assertion failed.\r\nTest failed"); TestResult result = await _testMethodInfo.InvokeAsync(null); diff --git a/test/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.FailInconclusive.cs b/test/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.FailInconclusive.cs new file mode 100644 index 0000000000..79b631d843 --- /dev/null +++ b/test/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.FailInconclusive.cs @@ -0,0 +1,56 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using AwesomeAssertions; + +namespace Microsoft.VisualStudio.TestPlatform.TestFramework.UnitTests; + +public partial class AssertTests +{ + public void FailWithoutMessageShouldUseStructuredPrefixOnly() + { + Action action = () => Assert.Fail(); + action.Should().Throw() + .WithMessage("Assertion failed."); + } + + public void FailWithMessageShouldPlaceUserMessageOnOwnLine() + { + Action action = () => Assert.Fail("custom reason"); + action.Should().Throw() + .WithMessage( + """ + Assertion failed. + custom reason + """); + } + + public void FailWithEmptyMessageShouldNotAddBlankLine() + { + Action action = () => Assert.Fail(string.Empty); + action.Should().Throw() + .WithMessage("Assertion failed."); + } + + public void InconclusiveWithoutMessageShouldUseInconclusivePrefix() + { + Action action = () => Assert.Inconclusive(); + action.Should().Throw() + .WithMessage("Assert.Inconclusive."); + } + + public void InconclusiveWithMessageShouldAppendUserMessage() + { + Action action = () => Assert.Inconclusive("db unavailable"); + action.Should().Throw() + .WithMessage("Assert.Inconclusive. db unavailable"); + } + + // See https://github.com/dotnet/sdk/issues/25373 + public void InconclusiveDoesNotThrowWhenMessageContainsInvalidStringFormatCompositeAndNoArgumentsPassed_Regression() + { + Action action = () => Assert.Inconclusive("{"); + action.Should().Throw() + .WithMessage("Assert.Inconclusive. {"); + } +} diff --git a/test/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.InconclusiveTests.cs b/test/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.InconclusiveTests.cs index d0b8d8fcc7..f580a72679 100644 --- a/test/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.InconclusiveTests.cs +++ b/test/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.InconclusiveTests.cs @@ -12,6 +12,6 @@ public void InconclusiveDoesNotThrowWhenMessageContainsInvalidStringFormatCompos { Action action = () => Assert.Inconclusive("{"); action.Should().Throw() - .And.Message.Should().Contain("Assert.Inconclusive failed. {"); + .And.Message.Should().Contain("Assert.Inconclusive. {"); } } diff --git a/test/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.ScopeTests.cs b/test/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.ScopeTests.cs index fe99ada571..6038f2c7fe 100644 --- a/test/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.ScopeTests.cs +++ b/test/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.ScopeTests.cs @@ -122,7 +122,11 @@ public void Scope_AssertFail_IsHardFailure() // Assert.Fail is a hard assertion — it throws immediately, even within a scope. action.Should().Throw() - .WithMessage("Assert.Fail failed. first failure"); + .WithMessage( + """ + Assertion failed. + first failure + """); } public void Scope_AssertIsNotNull_IsSoftFailure() From e24a4c57743fe33e83efa6808fc59d1d4d7733fa Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 17 May 2026 09:48:10 +0000 Subject: [PATCH 2/8] Fix review feedback for fail and inconclusive assertions Co-authored-by: Evangelink <11340282+Evangelink@users.noreply.github.com> --- .../MSTest.Acceptance.IntegrationTests/RetryTests.cs | 4 +++- .../Assertions/AssertTests.FailInconclusive.cs | 7 ------- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/RetryTests.cs b/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/RetryTests.cs index bcaf20e488..677ade2d2e 100644 --- a/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/RetryTests.cs +++ b/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/RetryTests.cs @@ -1,6 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. +using System; + using Microsoft.Testing.Platform.Acceptance.IntegrationTests; using Microsoft.Testing.Platform.Acceptance.IntegrationTests.Helpers; using Microsoft.Testing.Platform.Helpers; @@ -26,7 +28,7 @@ TestMethod5 executed 4 times. """); testHostResult.AssertOutputContains("failed TestMethod5"); - testHostResult.AssertOutputContains("Assertion failed.\r\nFailing TestMethod4. Attempts: 4 (from TestContext: 4)"); + testHostResult.AssertOutputContains($"Assertion failed.{Environment.NewLine}Failing TestMethod4. Attempts: 4 (from TestContext: 4)"); testHostResult.AssertOutputContainsSummary(failed: 1, passed: 4, skipped: 0); } diff --git a/test/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.FailInconclusive.cs b/test/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.FailInconclusive.cs index 79b631d843..53b9471fd8 100644 --- a/test/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.FailInconclusive.cs +++ b/test/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.FailInconclusive.cs @@ -46,11 +46,4 @@ public void InconclusiveWithMessageShouldAppendUserMessage() .WithMessage("Assert.Inconclusive. db unavailable"); } - // See https://github.com/dotnet/sdk/issues/25373 - public void InconclusiveDoesNotThrowWhenMessageContainsInvalidStringFormatCompositeAndNoArgumentsPassed_Regression() - { - Action action = () => Assert.Inconclusive("{"); - action.Should().Throw() - .WithMessage("Assert.Inconclusive. {"); - } } From 024ea6abbf77808effc4ecc15fae3eee47910d78 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 17 May 2026 19:41:23 +0000 Subject: [PATCH 3/8] Fix failing assertion message expectations Co-authored-by: Evangelink <11340282+Evangelink@users.noreply.github.com> --- .../GenericTestMethodTests.cs | 12 ++++++------ .../MSTest.Acceptance.IntegrationTests/RetryTests.cs | 5 ++--- .../SoftAssertionTests.cs | 2 +- .../Assertions/AssertTests.FailInconclusive.cs | 1 - 4 files changed, 9 insertions(+), 11 deletions(-) diff --git a/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/GenericTestMethodTests.cs b/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/GenericTestMethodTests.cs index 6581de34dc..76b083f269 100644 --- a/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/GenericTestMethodTests.cs +++ b/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/GenericTestMethodTests.cs @@ -27,13 +27,13 @@ public async Task TestDifferentGenericMethodTestCases() The generic test method 'NonParameterizedTestMethod' doesn't have arguments, so the generic parameter cannot be inferred\. .+? failed ParameterizedMethodSimple \(1\) \((\d+s )?\d+ms\) - Assert\.Fail failed\. Test method 'ParameterizedMethodSimple' did run with parameter '1' and type 'System\.Byte'\. + Assertion failed\.[\r\n]+\s+Test method 'ParameterizedMethodSimple' did run with parameter '1' and type 'System\.Byte'\. .+? failed ParameterizedMethodSimple \(2\) \((\d+s )?\d+ms\) - Assert\.Fail failed\. Test method 'ParameterizedMethodSimple' did run with parameter '2' and type 'System\.Int32'\. + Assertion failed\.[\r\n]+\s+Test method 'ParameterizedMethodSimple' did run with parameter '2' and type 'System\.Int32'\. .+? failed ParameterizedMethodSimple \("Hello world"\) \((\d+s )?\d+ms\) - Assert\.Fail failed\. Test method 'ParameterizedMethodSimple' did run with parameter 'Hello world' and type 'System\.String'\. + Assertion failed\.[\r\n]+\s+Test method 'ParameterizedMethodSimple' did run with parameter 'Hello world' and type 'System\.String'\. .+? failed ParameterizedMethodSimple \(null\) \((\d+s )?\d+ms\) Test method TestClass\.ParameterizedMethodSimple threw exception: @@ -44,7 +44,7 @@ public async Task TestDifferentGenericMethodTestCases() System\.InvalidOperationException: Found two conflicting types for generic parameter 'T2'\. The conflicting types are 'System\.Byte' and 'System\.Int32'\. .+? failed ParameterizedMethodTwoGenericParametersAndFourMethodParameters \(null,"Hello world","Hello again",3\) \((\d+s )?\d+ms\) - Assert\.Fail failed\. Test method 'ParameterizedMethodTwoGenericParametersAndFourMethodParameters' did run with parameters '', 'Hello world', 'Hello again', '3' and generic types 'System\.Int32', 'System\.String'\. + Assertion failed\.[\r\n]+\s+Test method 'ParameterizedMethodTwoGenericParametersAndFourMethodParameters' did run with parameters '', 'Hello world', 'Hello again', '3' and generic types 'System\.Int32', 'System\.String'\. .+? failed ParameterizedMethodTwoGenericParametersAndFourMethodParameters \("Hello hello","Hello world",null,null\) \((\d+s )?\d+ms\) Test method TestClass\.ParameterizedMethodTwoGenericParametersAndFourMethodParameters threw exception: @@ -70,10 +70,10 @@ Cannot create an instance of T\[] because Type\.ContainsGenericParameters is tru Cannot create an instance of T\[] because Type\.ContainsGenericParameters is true\. .+? failed ParameterizedMethodWithNestedGeneric \(System\.Collections\.Generic\.List`1\[System.String],System\.Collections\.Generic\.List`1\[System.String]\) \((\d+s )?\d+ms\) - Assert\.Fail failed\. Test method 'ParameterizedMethodWithNestedGeneric' did run with first list \[Hello, World] and second list \[Unit, Testing] + Assertion failed\.[\r\n]+\s+Test method 'ParameterizedMethodWithNestedGeneric' did run with first list \[Hello, World] and second list \[Unit, Testing] .+? failed ParameterizedMethodWithNestedGeneric \(System\.Collections\.Generic\.List`1\[System.Int32],System\.Collections\.Generic\.List`1\[System.Int32]\) \((\d+s )?\d+ms\) - Assert\.Fail failed\. Test method 'ParameterizedMethodWithNestedGeneric' did run with first list \[0, 1] and second list \[2, 3] + Assertion failed\.[\r\n]+\s+Test method 'ParameterizedMethodWithNestedGeneric' did run with first list \[0, 1] and second list \[2, 3] .+? """, RegexOptions.Singleline); } diff --git a/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/RetryTests.cs b/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/RetryTests.cs index 677ade2d2e..3305922e2a 100644 --- a/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/RetryTests.cs +++ b/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/RetryTests.cs @@ -1,8 +1,6 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -using System; - using Microsoft.Testing.Platform.Acceptance.IntegrationTests; using Microsoft.Testing.Platform.Acceptance.IntegrationTests.Helpers; using Microsoft.Testing.Platform.Helpers; @@ -28,7 +26,8 @@ TestMethod5 executed 4 times. """); testHostResult.AssertOutputContains("failed TestMethod5"); - testHostResult.AssertOutputContains($"Assertion failed.{Environment.NewLine}Failing TestMethod4. Attempts: 4 (from TestContext: 4)"); + testHostResult.AssertOutputMatchesRegex( + """Assertion failed\.[\r\n]+\s+Failing TestMethod4\. Attempts: 4 \(from TestContext: 4\)"""); testHostResult.AssertOutputContainsSummary(failed: 1, passed: 4, skipped: 0); } diff --git a/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/SoftAssertionTests.cs b/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/SoftAssertionTests.cs index 13129811e4..dd3fedd97a 100644 --- a/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/SoftAssertionTests.cs +++ b/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/SoftAssertionTests.cs @@ -54,7 +54,7 @@ public async Task AssertFailIsHardFailure_ThrowsImmediately() // Assert.Fail is a hard assertion — it throws immediately, even within a scope. // The second Assert.Fail should not be reached. testHostResult.AssertOutputMatchesRegex( - """failed AssertFailIsHardFailure \(\d+ms\)[\s\S]+Assert\.Fail failed\. hard failure"""); + """failed AssertFailIsHardFailure \(\d+ms\)[\s\S]+Assertion failed\.[\r\n]+\s+hard failure"""); testHostResult.AssertOutputDoesNotContain("second failure"); } diff --git a/test/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.FailInconclusive.cs b/test/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.FailInconclusive.cs index 53b9471fd8..58e8380175 100644 --- a/test/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.FailInconclusive.cs +++ b/test/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.FailInconclusive.cs @@ -45,5 +45,4 @@ public void InconclusiveWithMessageShouldAppendUserMessage() action.Should().Throw() .WithMessage("Assert.Inconclusive. db unavailable"); } - } From bb172a75afa8b50c90a56c4a8e3f77a3bead6ff3 Mon Sep 17 00:00:00 2001 From: Copilot <223556219+Copilot@users.noreply.github.com> Date: Mon, 18 May 2026 09:25:24 +0200 Subject: [PATCH 4/8] Use comparer type short name in AreAllDistinct failure message Aligns the failure message with the convention used by Assert.Contains (which uses GetType().Name) and fixes the unit test expectations in AssertTests.AreAll.cs that expected the short type name. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../TestFramework/Assertions/Assert.AreAllDistinct.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/TestFramework/TestFramework/Assertions/Assert.AreAllDistinct.cs b/src/TestFramework/TestFramework/Assertions/Assert.AreAllDistinct.cs index 0929bfe3dc..183ac9d884 100644 --- a/src/TestFramework/TestFramework/Assertions/Assert.AreAllDistinct.cs +++ b/src/TestFramework/TestFramework/Assertions/Assert.AreAllDistinct.cs @@ -67,7 +67,7 @@ public static void AreAllDistinct([NotNull] IEnumerable? collection, [NotN { CheckParameterNotNull(collection, "Assert.AreAllDistinct", "collection"); CheckParameterNotNull(comparer, "Assert.AreAllDistinct", "comparer"); - AreAllDistinctImpl(collection, comparer, comparerTypeName: comparer.GetType().ToString(), message, collectionExpression); + AreAllDistinctImpl(collection, comparer, comparerTypeName: comparer.GetType().Name, message, collectionExpression); } /// @@ -121,7 +121,7 @@ public static void AreAllDistinct([NotNull] IEnumerable? collection, [NotNull] I { CheckParameterNotNull(collection, "Assert.AreAllDistinct", "collection"); CheckParameterNotNull(comparer, "Assert.AreAllDistinct", "comparer"); - AreAllDistinctImpl(collection.Cast(), new NonGenericEqualityComparerAdapter(comparer), comparerTypeName: comparer.GetType().ToString(), message, collectionExpression); + AreAllDistinctImpl(collection.Cast(), new NonGenericEqualityComparerAdapter(comparer), comparerTypeName: comparer.GetType().Name, message, collectionExpression); } #pragma warning disable CS8714 // The type cannot be used as type parameter in the generic type or method. Nullability of type argument doesn't match 'notnull' constraint. From fe7b2c6db5e895292b25fb740ba94d6290f7e2e1 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 18 May 2026 08:48:20 +0000 Subject: [PATCH 5/8] Fix platform-specific assertion message expectations Co-authored-by: Evangelink <11340282+Evangelink@users.noreply.github.com> --- .../Execution/TestAssemblyInfoTests.cs | 4 ++-- .../Execution/TestClassInfoTests.cs | 4 ++-- .../Execution/TestMethodInfoTests.cs | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/TestAssemblyInfoTests.cs b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/TestAssemblyInfoTests.cs index 8450abb090..8aed4b537b 100644 --- a/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/TestAssemblyInfoTests.cs +++ b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/TestAssemblyInfoTests.cs @@ -146,7 +146,7 @@ public async Task RunAssemblyInitializeShouldThrowTestFailedExceptionOnAssertion var exception = (await _testAssemblyInfo.RunAssemblyInitializeAsync(_testContext)).TestFailureException as TestFailedException; exception.Should().NotBeNull(); exception.Outcome.Should().Be(UnitTestOutcome.Failed); - exception.Message.Should().Be("Assembly Initialization method Microsoft.VisualStudio.TestPlatform.MSTestAdapter.UnitTests.Execution.TestAssemblyInfoTests+DummyTestClass.AssemblyInitializeMethod threw exception. Microsoft.VisualStudio.TestTools.UnitTesting.AssertFailedException: Assertion failed.\r\nTest failure. Aborting test execution."); + exception.Message.Should().Be($"Assembly Initialization method Microsoft.VisualStudio.TestPlatform.MSTestAdapter.UnitTests.Execution.TestAssemblyInfoTests+DummyTestClass.AssemblyInitializeMethod threw exception. Microsoft.VisualStudio.TestTools.UnitTesting.AssertFailedException: Assertion failed.{global::System.Environment.NewLine}Test failure. Aborting test execution."); exception.StackTraceInformation!.ErrorStackTrace.Should().Contain( "Microsoft.VisualStudio.TestPlatform.MSTestAdapter.UnitTests.Execution.TestAssemblyInfoTests.DummyTestClass.AssemblyInitializeMethod"); exception.InnerException.Should().BeOfType(); @@ -264,7 +264,7 @@ public async Task RunAssemblyCleanupShouldReturnAssertFailureExceptionDetails() _testAssemblyInfo.AssemblyCleanupMethod = typeof(DummyTestClass).GetMethod("AssemblyCleanupMethod")!; string? actualErrorMessage = (await _testAssemblyInfo.ExecuteAssemblyCleanupAsync(GetTestContext()))?.Message; actualErrorMessage!.StartsWith( - "Assembly Cleanup method DummyTestClass.AssemblyCleanupMethod failed. Error Message: Assertion failed.\r\nTest Failure..", StringComparison.Ordinal).Should().BeTrue($"Value: {actualErrorMessage}"); + $"Assembly Cleanup method DummyTestClass.AssemblyCleanupMethod failed. Error Message: Assertion failed.{global::System.Environment.NewLine}Test Failure..", StringComparison.Ordinal).Should().BeTrue($"Value: {actualErrorMessage}"); } public async Task RunAssemblyCleanupShouldReturnAssertInconclusiveExceptionDetails() diff --git a/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/TestClassInfoTests.cs b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/TestClassInfoTests.cs index d131c9b542..218d5f4a4d 100644 --- a/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/TestClassInfoTests.cs +++ b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/TestClassInfoTests.cs @@ -350,7 +350,7 @@ public void RunClassInitializeShouldThrowTestFailedExceptionOnAssertionFailure() exception.Should().NotBeNull(); exception.Outcome.Should().Be(UnitTestOutcome.Failed); - exception.Message.Should().Be("Class Initialization method Microsoft.VisualStudio.TestPlatform.MSTestAdapter.UnitTests.Execution.TestClassInfoTests+DummyTestClass.ClassInitializeMethod threw exception. Microsoft.VisualStudio.TestTools.UnitTesting.AssertFailedException: Assertion failed.\r\nTest failure."); + exception.Message.Should().Be($"Class Initialization method Microsoft.VisualStudio.TestPlatform.MSTestAdapter.UnitTests.Execution.TestClassInfoTests+DummyTestClass.ClassInitializeMethod threw exception. Microsoft.VisualStudio.TestTools.UnitTesting.AssertFailedException: Assertion failed.{global::System.Environment.NewLine}Test failure."); exception.StackTraceInformation!.ErrorStackTrace.Contains( "Microsoft.VisualStudio.TestPlatform.MSTestAdapter.UnitTests.Execution.TestClassInfoTests.DummyTestClass.ClassInitializeMethod", StringComparison.Ordinal).Should().BeTrue(); exception.InnerException.Should().BeOfType(); @@ -481,7 +481,7 @@ public async Task RunClassCleanupShouldReturnAssertFailureExceptionDetails() // Assert classCleanupException.Should().NotBeNull(); classCleanupException.Message.StartsWith("Class Cleanup method DummyTestClass.ClassCleanupMethod failed.", StringComparison.Ordinal).Should().BeTrue(); - classCleanupException.Message.Contains("Error Message: Assertion failed.\r\nTest Failure.").Should().BeTrue(); + classCleanupException.Message.Contains($"Error Message: Assertion failed.{global::System.Environment.NewLine}Test Failure.").Should().BeTrue(); classCleanupException.Message.Should().Contain( $"{typeof(TestClassInfoTests).FullName}.DummyTestClass.ClassCleanupMethod", $"Value: {classCleanupException.Message}"); diff --git a/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/TestMethodInfoTests.cs b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/TestMethodInfoTests.cs index 8335a860c7..ebeb7786c8 100644 --- a/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/TestMethodInfoTests.cs +++ b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/TestMethodInfoTests.cs @@ -863,7 +863,7 @@ public async Task TestMethodInfoInvokeWhenTestThrowsAssertFailReturnsExpectedRes Resource.UTA_InitMethodThrows, typeof(DummyTestClass).FullName, _testClassInfo.TestInitializeMethod!.Name, - "Assertion failed.\r\ndummyFailMessage"); + $"Assertion failed.{global::System.Environment.NewLine}dummyFailMessage"); var testMethodInfo = new TestMethodInfo(_methodInfo, _testClassInfo) { @@ -1137,7 +1137,7 @@ public async Task TestMethodInfoInvokeWhenTestCleanupThrowsAssertFailedReturnsEx Resource.UTA_CleanupMethodThrows, typeof(DummyTestClass).FullName, _testClassInfo.TestCleanupMethod!.Name, - "Microsoft.VisualStudio.TestTools.UnitTesting.AssertFailedException: Assertion failed.\r\nTest failed"); + $"Microsoft.VisualStudio.TestTools.UnitTesting.AssertFailedException: Assertion failed.{global::System.Environment.NewLine}Test failed"); TestResult result = await _testMethodInfo.InvokeAsync(null); From 0296e77bff7d8b91e7efd914f5649df6163e5a57 Mon Sep 17 00:00:00 2001 From: Copilot <223556219+Copilot@users.noreply.github.com> Date: Mon, 18 May 2026 11:42:13 +0200 Subject: [PATCH 6/8] Address PR feedback and stabilize STAThreading test Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../STAThreadingTests.cs | 18 ++++++++---------- .../Execution/TestAssemblyInfoTests.cs | 4 ++-- .../Execution/TestClassInfoTests.cs | 4 ++-- .../Execution/TestMethodInfoTests.cs | 4 ++-- 4 files changed, 14 insertions(+), 16 deletions(-) diff --git a/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/STAThreadingTests.cs b/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/STAThreadingTests.cs index 1af404a082..bfea19b435 100644 --- a/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/STAThreadingTests.cs +++ b/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/STAThreadingTests.cs @@ -13,16 +13,12 @@ public sealed class STAThreadingTests : AcceptanceTestBase(); @@ -264,7 +264,7 @@ public async Task RunAssemblyCleanupShouldReturnAssertFailureExceptionDetails() _testAssemblyInfo.AssemblyCleanupMethod = typeof(DummyTestClass).GetMethod("AssemblyCleanupMethod")!; string? actualErrorMessage = (await _testAssemblyInfo.ExecuteAssemblyCleanupAsync(GetTestContext()))?.Message; actualErrorMessage!.StartsWith( - "Assembly Cleanup method DummyTestClass.AssemblyCleanupMethod failed. Error Message: Assertion failed.\r\nTest Failure..", StringComparison.Ordinal).Should().BeTrue($"Value: {actualErrorMessage}"); + $"Assembly Cleanup method DummyTestClass.AssemblyCleanupMethod failed. Error Message: Assertion failed.{Environment.NewLine}Test Failure..", StringComparison.Ordinal).Should().BeTrue($"Value: {actualErrorMessage}"); } public async Task RunAssemblyCleanupShouldReturnAssertInconclusiveExceptionDetails() diff --git a/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/TestClassInfoTests.cs b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/TestClassInfoTests.cs index d131c9b542..10ba7e293e 100644 --- a/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/TestClassInfoTests.cs +++ b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/TestClassInfoTests.cs @@ -350,7 +350,7 @@ public void RunClassInitializeShouldThrowTestFailedExceptionOnAssertionFailure() exception.Should().NotBeNull(); exception.Outcome.Should().Be(UnitTestOutcome.Failed); - exception.Message.Should().Be("Class Initialization method Microsoft.VisualStudio.TestPlatform.MSTestAdapter.UnitTests.Execution.TestClassInfoTests+DummyTestClass.ClassInitializeMethod threw exception. Microsoft.VisualStudio.TestTools.UnitTesting.AssertFailedException: Assertion failed.\r\nTest failure."); + exception.Message.Should().Be($"Class Initialization method Microsoft.VisualStudio.TestPlatform.MSTestAdapter.UnitTests.Execution.TestClassInfoTests+DummyTestClass.ClassInitializeMethod threw exception. Microsoft.VisualStudio.TestTools.UnitTesting.AssertFailedException: Assertion failed.{Environment.NewLine}Test failure."); exception.StackTraceInformation!.ErrorStackTrace.Contains( "Microsoft.VisualStudio.TestPlatform.MSTestAdapter.UnitTests.Execution.TestClassInfoTests.DummyTestClass.ClassInitializeMethod", StringComparison.Ordinal).Should().BeTrue(); exception.InnerException.Should().BeOfType(); @@ -481,7 +481,7 @@ public async Task RunClassCleanupShouldReturnAssertFailureExceptionDetails() // Assert classCleanupException.Should().NotBeNull(); classCleanupException.Message.StartsWith("Class Cleanup method DummyTestClass.ClassCleanupMethod failed.", StringComparison.Ordinal).Should().BeTrue(); - classCleanupException.Message.Contains("Error Message: Assertion failed.\r\nTest Failure.").Should().BeTrue(); + classCleanupException.Message.Contains($"Error Message: Assertion failed.{Environment.NewLine}Test Failure.").Should().BeTrue(); classCleanupException.Message.Should().Contain( $"{typeof(TestClassInfoTests).FullName}.DummyTestClass.ClassCleanupMethod", $"Value: {classCleanupException.Message}"); diff --git a/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/TestMethodInfoTests.cs b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/TestMethodInfoTests.cs index 8335a860c7..aa803a03b8 100644 --- a/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/TestMethodInfoTests.cs +++ b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/TestMethodInfoTests.cs @@ -863,7 +863,7 @@ public async Task TestMethodInfoInvokeWhenTestThrowsAssertFailReturnsExpectedRes Resource.UTA_InitMethodThrows, typeof(DummyTestClass).FullName, _testClassInfo.TestInitializeMethod!.Name, - "Assertion failed.\r\ndummyFailMessage"); + $"Assertion failed.{Environment.NewLine}dummyFailMessage"); var testMethodInfo = new TestMethodInfo(_methodInfo, _testClassInfo) { @@ -1137,7 +1137,7 @@ public async Task TestMethodInfoInvokeWhenTestCleanupThrowsAssertFailedReturnsEx Resource.UTA_CleanupMethodThrows, typeof(DummyTestClass).FullName, _testClassInfo.TestCleanupMethod!.Name, - "Microsoft.VisualStudio.TestTools.UnitTesting.AssertFailedException: Assertion failed.\r\nTest failed"); + $"Microsoft.VisualStudio.TestTools.UnitTesting.AssertFailedException: Assertion failed.{Environment.NewLine}Test failed"); TestResult result = await _testMethodInfo.InvokeAsync(null); From 1a434a4297d9ba1ab9f5c5c96fb9946237bb0cd3 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 18 May 2026 15:19:14 +0000 Subject: [PATCH 7/8] Deduplicate inconclusive message formatting Co-authored-by: Evangelink <11340282+Evangelink@users.noreply.github.com> --- .../TestFramework/Assertions/Assert.Inconclusive.cs | 6 +----- .../TestFramework/Assertions/Assert.cs | 13 ++++++++----- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/TestFramework/TestFramework/Assertions/Assert.Inconclusive.cs b/src/TestFramework/TestFramework/Assertions/Assert.Inconclusive.cs index 65d79b4ab5..af463176e3 100644 --- a/src/TestFramework/TestFramework/Assertions/Assert.Inconclusive.cs +++ b/src/TestFramework/TestFramework/Assertions/Assert.Inconclusive.cs @@ -30,9 +30,5 @@ public static void Inconclusive(string message = "") } private static string FormatInconclusive(string? message) - => string.IsNullOrWhiteSpace(message) - ? FrameworkMessages.InconclusivePrefix - : message![0] is '\n' or '\r' - ? string.Concat(FrameworkMessages.InconclusivePrefix, message) - : $"{FrameworkMessages.InconclusivePrefix} {message}"; + => FormatPrefixAndMessage(FrameworkMessages.InconclusivePrefix, message); } diff --git a/src/TestFramework/TestFramework/Assertions/Assert.cs b/src/TestFramework/TestFramework/Assertions/Assert.cs index 58da1d5525..daa9c365f0 100644 --- a/src/TestFramework/TestFramework/Assertions/Assert.cs +++ b/src/TestFramework/TestFramework/Assertions/Assert.cs @@ -248,13 +248,16 @@ private static string NormalizeCallSitePlaceholder(string placeholderOrParamName private static string FormatAssertionFailed(string assertionName, string? message) { string failedMessage = string.Format(CultureInfo.CurrentCulture, FrameworkMessages.AssertionFailed, assertionName); - return string.IsNullOrWhiteSpace(message) - ? failedMessage - : message![0] is '\n' or '\r' - ? string.Concat(failedMessage, message) - : $"{failedMessage} {message}"; + return FormatPrefixAndMessage(failedMessage, message); } + private static string FormatPrefixAndMessage(string prefix, string? message) + => string.IsNullOrWhiteSpace(message) + ? prefix + : message![0] is '\n' or '\r' + ? string.Concat(prefix, message) + : $"{prefix} {message}"; + /// /// Builds the formatted message using the given user format message and parameters. /// From c8a74ba93dfb91dc50ed84ab4676a4e8c3d3bcdd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amaury=20Lev=C3=A9?= Date: Mon, 18 May 2026 19:08:25 +0200 Subject: [PATCH 8/8] Use Environment.NewLine directly in interpolations The global:: namespace alias qualifier doesn't parse inside an interpolated string hole, which broke compilation of these test assertions. Drop the qualifier and rely on the implicit System using. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../Execution/TestAssemblyInfoTests.cs | 4 ++-- .../Execution/TestClassInfoTests.cs | 4 ++-- .../Execution/TestMethodInfoTests.cs | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/TestAssemblyInfoTests.cs b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/TestAssemblyInfoTests.cs index 8aed4b537b..2c300bcb84 100644 --- a/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/TestAssemblyInfoTests.cs +++ b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/TestAssemblyInfoTests.cs @@ -146,7 +146,7 @@ public async Task RunAssemblyInitializeShouldThrowTestFailedExceptionOnAssertion var exception = (await _testAssemblyInfo.RunAssemblyInitializeAsync(_testContext)).TestFailureException as TestFailedException; exception.Should().NotBeNull(); exception.Outcome.Should().Be(UnitTestOutcome.Failed); - exception.Message.Should().Be($"Assembly Initialization method Microsoft.VisualStudio.TestPlatform.MSTestAdapter.UnitTests.Execution.TestAssemblyInfoTests+DummyTestClass.AssemblyInitializeMethod threw exception. Microsoft.VisualStudio.TestTools.UnitTesting.AssertFailedException: Assertion failed.{global::System.Environment.NewLine}Test failure. Aborting test execution."); + exception.Message.Should().Be($"Assembly Initialization method Microsoft.VisualStudio.TestPlatform.MSTestAdapter.UnitTests.Execution.TestAssemblyInfoTests+DummyTestClass.AssemblyInitializeMethod threw exception. Microsoft.VisualStudio.TestTools.UnitTesting.AssertFailedException: Assertion failed.{Environment.NewLine}Test failure. Aborting test execution."); exception.StackTraceInformation!.ErrorStackTrace.Should().Contain( "Microsoft.VisualStudio.TestPlatform.MSTestAdapter.UnitTests.Execution.TestAssemblyInfoTests.DummyTestClass.AssemblyInitializeMethod"); exception.InnerException.Should().BeOfType(); @@ -264,7 +264,7 @@ public async Task RunAssemblyCleanupShouldReturnAssertFailureExceptionDetails() _testAssemblyInfo.AssemblyCleanupMethod = typeof(DummyTestClass).GetMethod("AssemblyCleanupMethod")!; string? actualErrorMessage = (await _testAssemblyInfo.ExecuteAssemblyCleanupAsync(GetTestContext()))?.Message; actualErrorMessage!.StartsWith( - $"Assembly Cleanup method DummyTestClass.AssemblyCleanupMethod failed. Error Message: Assertion failed.{global::System.Environment.NewLine}Test Failure..", StringComparison.Ordinal).Should().BeTrue($"Value: {actualErrorMessage}"); + $"Assembly Cleanup method DummyTestClass.AssemblyCleanupMethod failed. Error Message: Assertion failed.{Environment.NewLine}Test Failure..", StringComparison.Ordinal).Should().BeTrue($"Value: {actualErrorMessage}"); } public async Task RunAssemblyCleanupShouldReturnAssertInconclusiveExceptionDetails() diff --git a/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/TestClassInfoTests.cs b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/TestClassInfoTests.cs index 218d5f4a4d..10ba7e293e 100644 --- a/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/TestClassInfoTests.cs +++ b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/TestClassInfoTests.cs @@ -350,7 +350,7 @@ public void RunClassInitializeShouldThrowTestFailedExceptionOnAssertionFailure() exception.Should().NotBeNull(); exception.Outcome.Should().Be(UnitTestOutcome.Failed); - exception.Message.Should().Be($"Class Initialization method Microsoft.VisualStudio.TestPlatform.MSTestAdapter.UnitTests.Execution.TestClassInfoTests+DummyTestClass.ClassInitializeMethod threw exception. Microsoft.VisualStudio.TestTools.UnitTesting.AssertFailedException: Assertion failed.{global::System.Environment.NewLine}Test failure."); + exception.Message.Should().Be($"Class Initialization method Microsoft.VisualStudio.TestPlatform.MSTestAdapter.UnitTests.Execution.TestClassInfoTests+DummyTestClass.ClassInitializeMethod threw exception. Microsoft.VisualStudio.TestTools.UnitTesting.AssertFailedException: Assertion failed.{Environment.NewLine}Test failure."); exception.StackTraceInformation!.ErrorStackTrace.Contains( "Microsoft.VisualStudio.TestPlatform.MSTestAdapter.UnitTests.Execution.TestClassInfoTests.DummyTestClass.ClassInitializeMethod", StringComparison.Ordinal).Should().BeTrue(); exception.InnerException.Should().BeOfType(); @@ -481,7 +481,7 @@ public async Task RunClassCleanupShouldReturnAssertFailureExceptionDetails() // Assert classCleanupException.Should().NotBeNull(); classCleanupException.Message.StartsWith("Class Cleanup method DummyTestClass.ClassCleanupMethod failed.", StringComparison.Ordinal).Should().BeTrue(); - classCleanupException.Message.Contains($"Error Message: Assertion failed.{global::System.Environment.NewLine}Test Failure.").Should().BeTrue(); + classCleanupException.Message.Contains($"Error Message: Assertion failed.{Environment.NewLine}Test Failure.").Should().BeTrue(); classCleanupException.Message.Should().Contain( $"{typeof(TestClassInfoTests).FullName}.DummyTestClass.ClassCleanupMethod", $"Value: {classCleanupException.Message}"); diff --git a/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/TestMethodInfoTests.cs b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/TestMethodInfoTests.cs index ebeb7786c8..aa803a03b8 100644 --- a/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/TestMethodInfoTests.cs +++ b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/TestMethodInfoTests.cs @@ -863,7 +863,7 @@ public async Task TestMethodInfoInvokeWhenTestThrowsAssertFailReturnsExpectedRes Resource.UTA_InitMethodThrows, typeof(DummyTestClass).FullName, _testClassInfo.TestInitializeMethod!.Name, - $"Assertion failed.{global::System.Environment.NewLine}dummyFailMessage"); + $"Assertion failed.{Environment.NewLine}dummyFailMessage"); var testMethodInfo = new TestMethodInfo(_methodInfo, _testClassInfo) { @@ -1137,7 +1137,7 @@ public async Task TestMethodInfoInvokeWhenTestCleanupThrowsAssertFailedReturnsEx Resource.UTA_CleanupMethodThrows, typeof(DummyTestClass).FullName, _testClassInfo.TestCleanupMethod!.Name, - $"Microsoft.VisualStudio.TestTools.UnitTesting.AssertFailedException: Assertion failed.{global::System.Environment.NewLine}Test failed"); + $"Microsoft.VisualStudio.TestTools.UnitTesting.AssertFailedException: Assertion failed.{Environment.NewLine}Test failed"); TestResult result = await _testMethodInfo.InvokeAsync(null);