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/2] 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/2] 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. {"); - } }