diff --git a/src/Adapter/MSTest.TestAdapter/Execution/TestAssemblyInfo.cs b/src/Adapter/MSTest.TestAdapter/Execution/TestAssemblyInfo.cs
index 875c198231..34aaa264cf 100644
--- a/src/Adapter/MSTest.TestAdapter/Execution/TestAssemblyInfo.cs
+++ b/src/Adapter/MSTest.TestAdapter/Execution/TestAssemblyInfo.cs
@@ -234,4 +234,58 @@ public void RunAssemblyInitialize(TestContext testContext)
}
}
}
+
+ ///
+ /// Calls the assembly cleanup method in a thread-safe.
+ ///
+ ///
+ /// It is a replacement for RunAssemblyCleanup but as we are in a bug-fix version, we do not want to touch
+ /// public API and so we introduced this method.
+ ///
+ internal void ExecuteAssemblyCleanup()
+ {
+ if (AssemblyCleanupMethod == null)
+ {
+ return;
+ }
+
+ lock (_assemblyInfoExecuteSyncObject)
+ {
+ try
+ {
+ AssemblyCleanupMethod.InvokeAsSynchronousTask(null);
+ }
+ catch (Exception ex)
+ {
+ var realException = ex.InnerException ?? ex;
+
+ string errorMessage;
+
+ // special case AssertFailedException to trim off part of the stack trace
+ if (realException is AssertFailedException or AssertInconclusiveException)
+ {
+ errorMessage = realException.Message;
+ }
+ else
+ {
+ errorMessage = StackTraceHelper.GetExceptionMessage(realException);
+ }
+
+ var exceptionStackTraceInfo = StackTraceHelper.GetStackTraceInformation(realException);
+ DebugEx.Assert(AssemblyCleanupMethod.DeclaringType?.Name is not null, "AssemblyCleanupMethod.DeclaringType.Name is null");
+
+ throw new TestFailedException(
+ UnitTestOutcome.Failed,
+ string.Format(
+ CultureInfo.CurrentCulture,
+ Resource.UTA_AssemblyCleanupMethodWasUnsuccesful,
+ AssemblyCleanupMethod.DeclaringType.Name,
+ AssemblyCleanupMethod.Name,
+ errorMessage,
+ exceptionStackTraceInfo?.ErrorStackTrace),
+ exceptionStackTraceInfo,
+ realException);
+ }
+ }
+ }
}
diff --git a/src/Adapter/MSTest.TestAdapter/Execution/TestClassInfo.cs b/src/Adapter/MSTest.TestAdapter/Execution/TestClassInfo.cs
index 2f8d73d0e3..7fe9a419dc 100644
--- a/src/Adapter/MSTest.TestAdapter/Execution/TestClassInfo.cs
+++ b/src/Adapter/MSTest.TestAdapter/Execution/TestClassInfo.cs
@@ -410,4 +410,74 @@ public void RunClassInitialize(TestContext testContext)
return null;
}
+
+ ///
+ /// Execute current and base class cleanups.
+ ///
+ ///
+ /// This is a replacement for RunClassCleanup but as we are on a bug fix version, we do not want to change
+ /// the public API, hence this method.
+ ///
+ internal void ExecuteClassCleanup()
+ {
+ if ((ClassCleanupMethod is null && BaseClassInitAndCleanupMethods.All(p => p.Item2 == null))
+ || IsClassCleanupExecuted)
+ {
+ return;
+ }
+
+ lock (_testClassExecuteSyncObject)
+ {
+ if (IsClassCleanupExecuted
+ || (!IsClassInitializeExecuted && ClassInitializeMethod is not null))
+ {
+ return;
+ }
+
+ MethodInfo? classCleanupMethod = null;
+
+ try
+ {
+ classCleanupMethod = ClassCleanupMethod;
+ classCleanupMethod?.InvokeAsSynchronousTask(null);
+ var baseClassCleanupQueue = new Queue(BaseClassCleanupMethodsStack);
+ while (baseClassCleanupQueue.Count > 0)
+ {
+ classCleanupMethod = baseClassCleanupQueue.Dequeue();
+ classCleanupMethod?.InvokeAsSynchronousTask(null);
+ }
+
+ IsClassCleanupExecuted = true;
+
+ return;
+ }
+ catch (Exception exception)
+ {
+ var realException = exception.InnerException ?? exception;
+ ClassCleanupException = realException;
+
+ // special case AssertFailedException to trim off part of the stack trace
+ string errorMessage = realException is AssertFailedException or AssertInconclusiveException
+ ? realException.Message
+ : StackTraceHelper.GetExceptionMessage(realException);
+
+ var exceptionStackTraceInfo = realException.TryGetStackTraceInformation();
+
+ var testFailedException = new TestFailedException(
+ ObjectModelUnitTestOutcome.Failed,
+ string.Format(
+ CultureInfo.CurrentCulture,
+ Resource.UTA_ClassCleanupMethodWasUnsuccesful,
+ classCleanupMethod!.DeclaringType!.Name,
+ classCleanupMethod.Name,
+ errorMessage,
+ exceptionStackTraceInfo?.ErrorStackTrace),
+ exceptionStackTraceInfo,
+ realException);
+ ClassCleanupException = testFailedException;
+
+ throw testFailedException;
+ }
+ }
+ }
}
diff --git a/src/Adapter/MSTest.TestAdapter/Execution/UnitTestRunner.cs b/src/Adapter/MSTest.TestAdapter/Execution/UnitTestRunner.cs
index 619dda79cf..0041b7497f 100644
--- a/src/Adapter/MSTest.TestAdapter/Execution/UnitTestRunner.cs
+++ b/src/Adapter/MSTest.TestAdapter/Execution/UnitTestRunner.cs
@@ -141,7 +141,7 @@ internal UnitTestResult[] RunSingleTest(TestMethod testMethod, IDictionary
- /// Runs the class cleanup method.
- /// It returns any error information during the execution of the cleanup method.
- ///
- /// The .
- internal RunCleanupResult? RunClassAndAssemblyCleanup()
- {
- // No cleanup methods to execute, then return.
- var assemblyInfoCache = _typeCache.AssemblyInfoListWithExecutableCleanupMethods;
- var classInfoCache = _typeCache.ClassInfoListWithExecutableCleanupMethods;
- if (assemblyInfoCache.Length == 0 && classInfoCache.Length == 0)
- {
- return null;
- }
-
- var result = new RunCleanupResult { Warnings = new List() };
-
- using (var redirector = new LogMessageListener(MSTestSettings.CurrentSettings.CaptureDebugTraces))
- {
- try
- {
- RunClassCleanupMethods(classInfoCache, result.Warnings);
- RunAssemblyCleanup(assemblyInfoCache, result.Warnings);
- }
- finally
- {
- // Replacing the null character with a string.replace should work.
- // If this does not work for a specific dotnet version a custom function doing the same needs to be put in place.
- result.StandardOut = redirector.GetAndClearStandardOutput()?.Replace("\0", "\\0");
- result.StandardError = redirector.GetAndClearStandardError()?.Replace("\0", "\\0");
- result.DebugTrace = redirector.GetAndClearDebugTrace()?.Replace("\0", "\\0");
- }
- }
-
- return result;
- }
-
- private void RunCleanupsIfNeeded(ITestContext testContext, TestMethodInfo testMethodInfo, TestMethod testMethod, UnitTestResult[] results)
+ private void RunRequiredCleanups(ITestContext testContext, TestMethodInfo testMethodInfo, TestMethod testMethod, UnitTestResult[] results)
{
bool shouldRunClassCleanup = false;
bool shouldRunClassAndAssemblyCleanup = false;
_classCleanupManager?.MarkTestComplete(testMethodInfo, testMethod, out shouldRunClassCleanup, out shouldRunClassAndAssemblyCleanup);
+ using LogMessageListener logListener = new(MSTestSettings.CurrentSettings.CaptureDebugTraces);
try
{
- using LogMessageListener logListener = new(MSTestSettings.CurrentSettings.CaptureDebugTraces);
if (shouldRunClassCleanup)
{
- try
- {
- // Class cleanup can throw exceptions in which case we need to ensure that we fail the test.
- testMethodInfo.Parent.RunClassCleanup(ClassCleanupBehavior.EndOfClass);
- }
- finally
- {
- string cleanupLogs = logListener.StandardOutput;
- string? cleanupTrace = logListener.DebugTrace;
- string cleanupErrorLogs = logListener.StandardError;
- var cleanupTestContextMessages = testContext.GetAndClearDiagnosticMessages();
-
- if (results.Length > 0)
- {
- var lastResult = results[results.Length - 1];
- lastResult.StandardOut += cleanupLogs;
- lastResult.StandardError += cleanupErrorLogs;
- lastResult.DebugTrace += cleanupTrace;
- lastResult.TestContextMessages += cleanupTestContextMessages;
- }
- }
+ testMethodInfo.Parent.ExecuteClassCleanup();
}
if (shouldRunClassAndAssemblyCleanup)
{
- try
+ var classInfoCache = _typeCache.ClassInfoListWithExecutableCleanupMethods;
+ foreach (var classInfo in classInfoCache)
{
- RunClassAndAssemblyCleanup();
+ classInfo.ExecuteClassCleanup();
}
- finally
- {
- string cleanupLogs = logListener.StandardOutput;
- string? cleanupTrace = logListener.DebugTrace;
- string cleanupErrorLogs = logListener.StandardError;
- var cleanupTestContextMessages = testContext.GetAndClearDiagnosticMessages();
- if (results.Length > 0)
- {
- var lastResult = results[results.Length - 1];
- lastResult.StandardOut += cleanupLogs;
- lastResult.StandardError += cleanupErrorLogs;
- lastResult.DebugTrace += cleanupTrace;
- lastResult.TestContextMessages += cleanupTestContextMessages;
- }
+ var assemblyInfoCache = _typeCache.AssemblyInfoListWithExecutableCleanupMethods;
+ foreach (var assemblyInfo in assemblyInfoCache)
+ {
+ assemblyInfo.ExecuteAssemblyCleanup();
}
}
}
- catch (Exception e)
+ catch (Exception ex)
{
+ // We mainly expect TestFailedException here as each cleanup method is executed in a try-catch block but
+ // for the sake of the catch-all mechanism, let's keep it as Exception.
+ if (results.Length == 0)
+ {
+ return;
+ }
+
+ var lastResult = results[results.Length - 1];
+ lastResult.Outcome = ObjectModel.UnitTestOutcome.Failed;
+ lastResult.ErrorMessage = ex.Message;
+ lastResult.ErrorStackTrace = ex.StackTrace;
+ }
+ finally
+ {
+ var cleanupTestContextMessages = testContext.GetAndClearDiagnosticMessages();
+
if (results.Length > 0)
{
- results[results.Length - 1].Outcome = ObjectModel.UnitTestOutcome.Failed;
- results[results.Length - 1].ErrorMessage = e.Message;
- results[results.Length - 1].ErrorStackTrace = e.StackTrace;
+ var lastResult = results[results.Length - 1];
+ lastResult.StandardOut += logListener.StandardOutput;
+ lastResult.StandardError += logListener.StandardError;
+ lastResult.DebugTrace += logListener.DebugTrace;
+ lastResult.TestContextMessages += cleanupTestContextMessages;
}
}
}
@@ -331,44 +283,6 @@ private bool IsTestMethodRunnable(
return true;
}
- ///
- /// Run assembly cleanup methods.
- ///
- /// The assembly Info Cache.
- /// The warnings.
- private static void RunAssemblyCleanup(IEnumerable assemblyInfoCache, IList warnings)
- {
- foreach (var assemblyInfo in assemblyInfoCache)
- {
- DebugEx.Assert(assemblyInfo.HasExecutableCleanupMethod, "HasExecutableCleanupMethod should be true.");
-
- var warning = assemblyInfo.RunAssemblyCleanup();
- if (warning != null)
- {
- warnings.Add(warning);
- }
- }
- }
-
- ///
- /// Run class cleanup methods.
- ///
- /// The class Info Cache.
- /// The warnings.
- private static void RunClassCleanupMethods(IEnumerable classInfoCache, IList warnings)
- {
- foreach (var classInfo in classInfoCache)
- {
- DebugEx.Assert(classInfo.HasExecutableCleanupMethod, "HasExecutableCleanupMethod should be true.");
-
- var warning = classInfo.RunClassCleanup();
- if (warning != null)
- {
- warnings.Add(warning);
- }
- }
- }
-
private class ClassCleanupManager
{
private readonly ClassCleanupBehavior? _lifecycleFromMsTest;
@@ -385,30 +299,33 @@ public ClassCleanupManager(
_remainingTestsByClass = testsToRun.GroupBy(t => t.TestMethod.FullClassName)
.ToDictionary(
g => g.Key,
- g => new HashSet(g.Select(t => t.DisplayName!)));
+ g => new HashSet(g.Select(t => t.TestMethod.UniqueName)));
_lifecycleFromMsTest = lifecycleFromMsTest;
_lifecycleFromAssembly = lifecycleFromAssembly;
_reflectHelper = reflectHelper ?? new ReflectHelper();
}
- public void MarkTestComplete(TestMethodInfo testMethodInfo, TestMethod testMethod, out bool shouldRunClassCleanup, out bool shouldRunAssemblyCleanup)
+ public void MarkTestComplete(TestMethodInfo testMethodInfo, TestMethod testMethod, out bool shouldRunEndOfClassCleanup, out bool shouldRunEndOfAssemblyCleanup)
{
- shouldRunClassCleanup = false;
+ shouldRunEndOfClassCleanup = false;
var testsByClass = _remainingTestsByClass[testMethodInfo.TestClassName];
lock (testsByClass)
{
- testsByClass.Remove(testMethod.DisplayName!);
- if (testsByClass.Count == 0 && testMethodInfo.Parent.HasExecutableCleanupMethod)
+ testsByClass.Remove(testMethod.UniqueName);
+ if (testsByClass.Count == 0)
{
- var cleanupLifecycle = _reflectHelper.GetClassCleanupBehavior(testMethodInfo.Parent)
- ?? _lifecycleFromMsTest
- ?? _lifecycleFromAssembly;
-
- shouldRunClassCleanup = cleanupLifecycle == ClassCleanupBehavior.EndOfClass;
_remainingTestsByClass.Remove(testMethodInfo.TestClassName);
+ if (testMethodInfo.Parent.HasExecutableCleanupMethod)
+ {
+ var cleanupLifecycle = _reflectHelper.GetClassCleanupBehavior(testMethodInfo.Parent)
+ ?? _lifecycleFromMsTest
+ ?? _lifecycleFromAssembly;
+
+ shouldRunEndOfClassCleanup = cleanupLifecycle == ClassCleanupBehavior.EndOfClass;
+ }
}
- shouldRunAssemblyCleanup = _remainingTestsByClass.Count == 0;
+ shouldRunEndOfAssemblyCleanup = _remainingTestsByClass.Count == 0;
}
}
}
diff --git a/src/Adapter/MSTest.TestAdapter/ObjectModel/TestMethod.cs b/src/Adapter/MSTest.TestAdapter/ObjectModel/TestMethod.cs
index d1a5da3a6b..cc51df2107 100644
--- a/src/Adapter/MSTest.TestAdapter/ObjectModel/TestMethod.cs
+++ b/src/Adapter/MSTest.TestAdapter/ObjectModel/TestMethod.cs
@@ -5,6 +5,7 @@
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics.CodeAnalysis;
+using System.Linq;
using System.Reflection;
using Microsoft.TestPlatform.AdapterUtilities;
@@ -173,5 +174,10 @@ public string? DeclaringClassFullName
///
internal string? DisplayName { get; set; }
+ internal string UniqueName
+ => HasManagedMethodAndTypeProperties
+ ? $"{ManagedTypeName}.{ManagedMethodName}->{string.Join(", ", SerializedData ?? Array.Empty())}"
+ : $"{FullClassName}.{Name}->{string.Join(", ", SerializedData ?? Array.Empty())}";
+
internal TestMethod Clone() => (TestMethod)MemberwiseClone();
}
diff --git a/test/E2ETests/Smoke.E2E.Tests/SuiteLifeCycleTests.cs b/test/E2ETests/Smoke.E2E.Tests/SuiteLifeCycleTests.cs
index 2306f26dc9..e66180f368 100644
--- a/test/E2ETests/Smoke.E2E.Tests/SuiteLifeCycleTests.cs
+++ b/test/E2ETests/Smoke.E2E.Tests/SuiteLifeCycleTests.cs
@@ -1423,7 +1423,7 @@ LifeCycleClassCleanupEndOfClassAndNone.TestCleanup was called
// Locally, netfx calls seems to be respecting the order of the cleanup while it is not stable for netcore.
// But local order is not the same on various machines. I am not sure whether we should be committing to a
// specific order.
- caseDerivedClassInitializeNoneAndClassCleanupBeforeEachDerivedClassParentTestMethod.Messages[0].Text.Should().Be(
+ var expectedStart =
$"""
Console: LifeCycleClassInitializeNoneAndClassCleanupBeforeEachDerivedClass.ctor was called
Console: LifeCycleDerivedClassInitializeNoneAndClassCleanupBeforeEachDerivedClass.ctor was called
@@ -1436,8 +1436,41 @@ LifeCycleClassCleanupEndOfClassAndNone.TestCleanup was called
? "Console: LifeCycleClassInitializeNoneAndClassCleanupBeforeEachDerivedClass.DisposeAsync was called\r\nConsole: LifeCycleClassInitializeNoneAndClassCleanupBeforeEachDerivedClass.Dispose was called"
: "Console: LifeCycleClassInitializeNoneAndClassCleanupBeforeEachDerivedClass.Dispose was called")}
- """);
- caseDerivedClassInitializeNoneAndClassCleanupBeforeEachDerivedClassParentTestMethod.Messages[1].Text.Should().Be(
+ """;
+ caseDerivedClassInitializeNoneAndClassCleanupBeforeEachDerivedClassParentTestMethod
+ .Messages[0].Text
+ .Should().StartWith(expectedStart);
+
+ var expectedRemainingMessages =
+ """
+ Console: LifeCycleDerivedClassInitializeNoneAndClassCleanupBeforeEachDerivedClass.ClassCleanup was called
+ Console: LifeCycleClassCleanup.ClassCleanup was called
+ Console: LifeCycleClassCleanupEndOfAssemblyAndBeforeEachDerivedClass.ClassCleanup was called
+ Console: LifeCycleClassInitializeNoneAndClassCleanupBeforeEachDerivedClass.ClassCleanup was called
+ Console: LifeCycleDerivedClassCleanupEndOfAssemblyAndNone.ClassCleanup was called
+ Console: LifeCycleDerivedClassInitializeAndCleanupNone.ClassCleanup was called
+ Console: LifeCycleClassInitializeAndCleanupNone.ClassCleanup was called
+ Console: LifeCycleDerivedClassInitializeAndCleanupBeforeEachDerivedClass.ClassCleanup was called
+ Console: LifeCycleClassInitializeAndCleanupBeforeEachDerivedClass.ClassCleanup was called
+ Console: LifeCycleDerivedClassCleanupEndOfClassAndBeforeEachDerivedClass.ClassCleanup was called
+ Console: LifeCycleClassInitializeAndCleanupBeforeEachDerivedClass.ClassCleanup was called
+ Console: LifeCycleDerivedClassCleanupEndOfAssemblyAndBeforeEachDerivedClass.ClassCleanup was called
+ Console: LifeCycleDerivedClassInitializeBeforeEachDerivedClassAndClassCleanupNone.ClassCleanup was called
+ Console: LifeCycleDerivedClassCleanupEndOfClassAndNone.ClassCleanup was called
+ Console: LifeCycleClassInitializeBeforeEachDerivedClassAndClassCleanupNone.ClassCleanup was called
+ Console: LifeCycleClassCleanupEndOfAssembly.ClassCleanup was called
+ Console: LifeCycleClassCleanupEndOfAssemblyAndNone.ClassCleanup was called
+ Console: AssemblyCleanup was called
+
+ """
+ .Split(new[] { "\r\n" }, StringSplitOptions.None);
+ caseDerivedClassInitializeNoneAndClassCleanupBeforeEachDerivedClassParentTestMethod
+ .Messages[0].Text
+ .Substring(expectedStart.Length)
+ .Split(new[] { "\r\n" }, StringSplitOptions.None)
+ .Should().BeEquivalentTo(expectedRemainingMessages);
+
+ expectedStart =
$"""
@@ -1455,9 +1488,41 @@ LifeCycleClassCleanupEndOfClassAndNone.TestCleanup was called
+ GenerateTraceDebugPrefixedMessage("LifeCycleClassInitializeNoneAndClassCleanupBeforeEachDerivedClass.Dispose was called")
: GenerateTraceDebugPrefixedMessage("LifeCycleClassInitializeNoneAndClassCleanupBeforeEachDerivedClass.Dispose was called"))}
- """);
+ """;
+ caseDerivedClassInitializeNoneAndClassCleanupBeforeEachDerivedClassParentTestMethod
+ .Messages[1].Text
+ .Should().StartWith(expectedStart);
+
+ expectedRemainingMessages =
+ $"""
+ {GenerateTraceDebugPrefixedMessage("LifeCycleDerivedClassCleanupEndOfClassAndNone.ClassCleanup was called")}
+ {GenerateTraceDebugPrefixedMessage("LifeCycleDerivedClassCleanupEndOfAssemblyAndBeforeEachDerivedClass.ClassCleanup was called")}
+ {GenerateTraceDebugPrefixedMessage("LifeCycleClassInitializeAndCleanupNone.ClassCleanup was called")}
+ {GenerateTraceDebugPrefixedMessage("LifeCycleClassCleanupEndOfAssemblyAndNone.ClassCleanup was called")}
+ {GenerateTraceDebugPrefixedMessage("LifeCycleDerivedClassInitializeBeforeEachDerivedClassAndClassCleanupNone.ClassCleanup was called")}
+ {GenerateTraceDebugPrefixedMessage("LifeCycleClassCleanup.ClassCleanup was called")}
+ {GenerateTraceDebugPrefixedMessage("LifeCycleDerivedClassInitializeNoneAndClassCleanupBeforeEachDerivedClass.ClassCleanup was called")}
+ {GenerateTraceDebugPrefixedMessage("LifeCycleClassInitializeBeforeEachDerivedClassAndClassCleanupNone.ClassCleanup was called")}
+ {GenerateTraceDebugPrefixedMessage("LifeCycleDerivedClassInitializeAndCleanupNone.ClassCleanup was called")}
+ {GenerateTraceDebugPrefixedMessage("LifeCycleClassCleanupEndOfAssembly.ClassCleanup was called")}
+ {GenerateTraceDebugPrefixedMessage("LifeCycleDerivedClassInitializeAndCleanupBeforeEachDerivedClass.ClassCleanup was called")}
+ {GenerateTraceDebugPrefixedMessage("LifeCycleClassInitializeAndCleanupBeforeEachDerivedClass.ClassCleanup was called")}
+ {GenerateTraceDebugPrefixedMessage("LifeCycleDerivedClassCleanupEndOfClassAndBeforeEachDerivedClass.ClassCleanup was called")}
+ {GenerateTraceDebugPrefixedMessage("LifeCycleClassCleanupEndOfAssemblyAndBeforeEachDerivedClass.ClassCleanup was called")}
+ {GenerateTraceDebugPrefixedMessage("LifeCycleDerivedClassCleanupEndOfAssemblyAndNone.ClassCleanup was called")}
+ {GenerateTraceDebugPrefixedMessage("LifeCycleClassInitializeNoneAndClassCleanupBeforeEachDerivedClass.ClassCleanup was called")}
+ {GenerateTraceDebugPrefixedMessage("LifeCycleClassInitializeAndCleanupBeforeEachDerivedClass.ClassCleanup was called")}
+ {GenerateTraceDebugPrefixedMessage("AssemblyCleanup was called")}
+
+ """
+ .Split(new[] { "\r\n" }, StringSplitOptions.None);
+ caseDerivedClassInitializeNoneAndClassCleanupBeforeEachDerivedClassParentTestMethod
+ .Messages[1].Text
+ .Substring(expectedStart.Length)
+ .Split(new[] { "\r\n" }, StringSplitOptions.None)
+ .Should().BeEquivalentTo(expectedRemainingMessages);
- var expectedStart =
+ expectedStart =
$"""
@@ -1474,30 +1539,33 @@ LifeCycleClassInitializeNoneAndClassCleanupBeforeEachDerivedClass.TestCleanup wa
: "LifeCycleClassInitializeNoneAndClassCleanupBeforeEachDerivedClass.Dispose was called")}
""";
- caseDerivedClassInitializeNoneAndClassCleanupBeforeEachDerivedClassParentTestMethod.Messages[2].Text.Should().StartWith(expectedStart);
- var expectedRemainingMessages = new List
- {
- "LifeCycleDerivedClassInitializeNoneAndClassCleanupBeforeEachDerivedClass.ClassCleanup was called",
- "LifeCycleClassCleanupEndOfAssemblyAndBeforeEachDerivedClass.ClassCleanup was called",
- "LifeCycleDerivedClassCleanupEndOfAssemblyAndNone.ClassCleanup was called",
- "LifeCycleDerivedClassCleanupEndOfClassAndBeforeEachDerivedClass.ClassCleanup was called",
- "LifeCycleDerivedClassCleanupEndOfAssemblyAndBeforeEachDerivedClass.ClassCleanup was called",
- "LifeCycleDerivedClassCleanupEndOfClassAndNone.ClassCleanup was called",
- "LifeCycleClassCleanupEndOfAssemblyAndNone.ClassCleanup was called",
- "LifeCycleClassCleanup.ClassCleanup was called",
- "LifeCycleClassInitializeNoneAndClassCleanupBeforeEachDerivedClass.ClassCleanup was called",
- "LifeCycleDerivedClassInitializeAndCleanupNone.ClassCleanup was called",
- "LifeCycleClassInitializeAndCleanupNone.ClassCleanup was called",
- "LifeCycleDerivedClassInitializeAndCleanupBeforeEachDerivedClass.ClassCleanup was called",
- "LifeCycleClassInitializeAndCleanupBeforeEachDerivedClass.ClassCleanup was called",
- "LifeCycleClassInitializeAndCleanupBeforeEachDerivedClass.ClassCleanup was called",
- "LifeCycleDerivedClassInitializeBeforeEachDerivedClassAndClassCleanupNone.ClassCleanup was called",
- "LifeCycleClassInitializeBeforeEachDerivedClassAndClassCleanupNone.ClassCleanup was called",
- "LifeCycleClassCleanupEndOfAssembly.ClassCleanup was called",
- "AssemblyCleanup was called",
- string.Empty,
- };
-
+ caseDerivedClassInitializeNoneAndClassCleanupBeforeEachDerivedClassParentTestMethod
+ .Messages[2].Text
+ .Should().StartWith(expectedStart);
+
+ expectedRemainingMessages =
+ """
+ LifeCycleDerivedClassInitializeNoneAndClassCleanupBeforeEachDerivedClass.ClassCleanup was called
+ LifeCycleClassCleanupEndOfAssemblyAndBeforeEachDerivedClass.ClassCleanup was called
+ LifeCycleDerivedClassCleanupEndOfAssemblyAndNone.ClassCleanup was called
+ LifeCycleDerivedClassCleanupEndOfClassAndBeforeEachDerivedClass.ClassCleanup was called
+ LifeCycleDerivedClassCleanupEndOfAssemblyAndBeforeEachDerivedClass.ClassCleanup was called
+ LifeCycleDerivedClassCleanupEndOfClassAndNone.ClassCleanup was called
+ LifeCycleClassCleanupEndOfAssemblyAndNone.ClassCleanup was called
+ LifeCycleClassCleanup.ClassCleanup was called
+ LifeCycleClassInitializeNoneAndClassCleanupBeforeEachDerivedClass.ClassCleanup was called
+ LifeCycleDerivedClassInitializeAndCleanupNone.ClassCleanup was called
+ LifeCycleClassInitializeAndCleanupNone.ClassCleanup was called
+ LifeCycleDerivedClassInitializeAndCleanupBeforeEachDerivedClass.ClassCleanup was called
+ LifeCycleClassInitializeAndCleanupBeforeEachDerivedClass.ClassCleanup was called
+ LifeCycleClassInitializeAndCleanupBeforeEachDerivedClass.ClassCleanup was called
+ LifeCycleDerivedClassInitializeBeforeEachDerivedClassAndClassCleanupNone.ClassCleanup was called
+ LifeCycleClassInitializeBeforeEachDerivedClassAndClassCleanupNone.ClassCleanup was called
+ LifeCycleClassCleanupEndOfAssembly.ClassCleanup was called
+ AssemblyCleanup was called
+
+ """
+ .Split(new[] { "\r\n" }, StringSplitOptions.None);
caseDerivedClassInitializeNoneAndClassCleanupBeforeEachDerivedClassParentTestMethod
.Messages[2].Text
.Substring(expectedStart.Length)
@@ -1505,7 +1573,7 @@ LifeCycleClassInitializeNoneAndClassCleanupBeforeEachDerivedClass.TestCleanup wa
.Should().BeEquivalentTo(expectedRemainingMessages);
}
- private string GenerateTraceDebugPrefixedMessage(string message)
+ private static string GenerateTraceDebugPrefixedMessage(string message)
{
string prefixedMessage = $"Trace: {message}";
diff --git a/test/UnitTests/MSTestAdapter.UnitTests/Execution/UnitTestRunnerTests.cs b/test/UnitTests/MSTestAdapter.UnitTests/Execution/UnitTestRunnerTests.cs
index dafaff85ed..5ddb830611 100644
--- a/test/UnitTests/MSTestAdapter.UnitTests/Execution/UnitTestRunnerTests.cs
+++ b/test/UnitTests/MSTestAdapter.UnitTests/Execution/UnitTestRunnerTests.cs
@@ -318,49 +318,6 @@ public void RunSingleTestShouldCallAssemblyInitializeAndClassInitializeMethodsIn
#endregion
- #region RunCleanup Tests
-
- public void RunCleanupShouldReturnNullOnNoCleanUpMethods()
- {
- Verify(_unitTestRunner.RunClassAndAssemblyCleanup() is null);
- }
-
- public void RunCleanupShouldReturnCleanupResultsForAssemblyAndClassCleanupMethods()
- {
- var type = typeof(DummyTestClassWithCleanupMethods);
- var methodInfo = type.GetMethod("TestMethod");
- var testMethod = new TestMethod(methodInfo.Name, type.FullName, "A", isAsync: false);
-
- _testablePlatformServiceProvider.MockFileOperations.Setup(fo => fo.LoadAssembly("A", It.IsAny()))
- .Returns(Assembly.GetExecutingAssembly());
-
- _unitTestRunner.RunSingleTest(testMethod, _testRunParameters);
-
- var assemblyCleanupCount = 0;
- var classCleanupCount = 0;
-
- DummyTestClassWithCleanupMethods.AssemblyCleanupMethodBody = () =>
- {
- assemblyCleanupCount++;
- throw new NotImplementedException();
- };
-
- DummyTestClassWithCleanupMethods.ClassCleanupMethodBody = () =>
- {
- classCleanupCount++;
- throw new NotImplementedException();
- };
-
- var cleanupresult = _unitTestRunner.RunClassAndAssemblyCleanup();
-
- Verify(assemblyCleanupCount == 1);
- Verify(classCleanupCount == 1);
- Verify(cleanupresult.Warnings.Count == 2);
- Verify(cleanupresult.Warnings.All(w => w.Contains("NotImplemented")));
- }
-
- #endregion
-
#region private helpers
private MSTestSettings GetSettingsWithDebugTrace(bool captureDebugTraceValue)