Skip to content

Commit c16a782

Browse files
authored
Fix running cleanup after first test method (#3766)
1 parent c00df3c commit c16a782

File tree

2 files changed

+66
-3
lines changed

2 files changed

+66
-3
lines changed

src/Adapter/MSTest.TestAdapter/Execution/ClassCleanupManager.cs

+3-3
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ internal sealed class ClassCleanupManager
1414
private readonly ClassCleanupBehavior? _lifecycleFromMsTest;
1515
private readonly ClassCleanupBehavior _lifecycleFromAssembly;
1616
private readonly ReflectHelper _reflectHelper;
17-
private readonly ConcurrentDictionary<string, HashSet<string>> _remainingTestsByClass;
17+
private readonly ConcurrentDictionary<string, List<string>> _remainingTestsByClass;
1818

1919
public ClassCleanupManager(
2020
IEnumerable<UnitTestElement> testsToRun,
@@ -27,7 +27,7 @@ public ClassCleanupManager(
2727
new(runnableTests.GroupBy(t => t.TestMethod.FullClassName)
2828
.ToDictionary(
2929
g => g.Key,
30-
g => new HashSet<string>(g.Select(t => t.TestMethod.UniqueName))));
30+
g => new List<string>(g.Select(t => t.TestMethod.UniqueName))));
3131
_lifecycleFromMsTest = lifecycleFromMsTest;
3232
_lifecycleFromAssembly = lifecycleFromAssembly;
3333
_reflectHelper = reflectHelper;
@@ -38,7 +38,7 @@ public ClassCleanupManager(
3838
public void MarkTestComplete(TestMethodInfo testMethodInfo, TestMethod testMethod, out bool shouldRunEndOfClassCleanup)
3939
{
4040
shouldRunEndOfClassCleanup = false;
41-
if (!_remainingTestsByClass.TryGetValue(testMethodInfo.TestClassName, out HashSet<string>? testsByClass))
41+
if (!_remainingTestsByClass.TryGetValue(testMethodInfo.TestClassName, out List<string>? testsByClass))
4242
{
4343
return;
4444
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
3+
4+
using System.Reflection;
5+
6+
using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution;
7+
using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Helpers;
8+
using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel;
9+
using Microsoft.VisualStudio.TestTools.UnitTesting;
10+
11+
using Moq;
12+
13+
using TestFramework.ForTestingMSTest;
14+
15+
namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.UnitTests.Execution;
16+
17+
public class ClassCleanupManagerTests : TestContainer
18+
{
19+
public void AssemblyCleanupRunsAfterAllTestsFinishEvenIfWeScheduleTheSameTestMultipleTime()
20+
{
21+
ReflectHelper reflectHelper = Mock.Of<ReflectHelper>();
22+
MethodInfo methodInfo = typeof(ClassCleanupManagerTests).GetMethod(nameof(FakeTestMethod), BindingFlags.Instance | BindingFlags.NonPublic);
23+
MethodInfo classCleanupMethodInfo = typeof(ClassCleanupManagerTests).GetMethod(nameof(FakeClassCleanupMethod), BindingFlags.Instance | BindingFlags.NonPublic);
24+
// Full class name must agree between unitTestElement.TestMethod.FullClassName and testMethod.FullClassName;
25+
string fullClassName = methodInfo.DeclaringType.FullName;
26+
TestMethod testMethod = new(nameof(FakeTestMethod), fullClassName, typeof(ClassCleanupManagerTests).Assembly.FullName, isAsync: false);
27+
28+
// Setting 2 of the same test to run, we should run assembly cleanup after both these tests
29+
// finish, not after the first one finishes.
30+
List<UnitTestElement> testsToRun = new()
31+
{
32+
new(testMethod),
33+
new(testMethod),
34+
};
35+
36+
var classCleanupManager = new ClassCleanupManager(testsToRun, ClassCleanupBehavior.EndOfClass, ClassCleanupBehavior.EndOfClass, reflectHelper);
37+
38+
TestClassInfo testClassInfo = new(typeof(ClassCleanupManagerTests), null, true, null, null, null)
39+
{
40+
// This needs to be set, to allow running class cleanup.
41+
ClassCleanupMethod = classCleanupMethodInfo,
42+
};
43+
TestMethodInfo testMethodInfo = new(methodInfo, testClassInfo, null!);
44+
classCleanupManager.MarkTestComplete(testMethodInfo, testMethod, out bool shouldRunEndOfClassCleanup);
45+
46+
// The cleanup should not run here yet, we have 1 remaining test to run.
47+
Assert.IsFalse(shouldRunEndOfClassCleanup);
48+
Assert.IsFalse(classCleanupManager.ShouldRunEndOfAssemblyCleanup);
49+
50+
classCleanupManager.MarkTestComplete(testMethodInfo, testMethod, out shouldRunEndOfClassCleanup);
51+
// The cleanup should run here.
52+
Assert.IsTrue(shouldRunEndOfClassCleanup);
53+
Assert.IsTrue(classCleanupManager.ShouldRunEndOfAssemblyCleanup);
54+
}
55+
56+
private void FakeTestMethod()
57+
{
58+
}
59+
60+
private void FakeClassCleanupMethod()
61+
{
62+
}
63+
}

0 commit comments

Comments
 (0)