Skip to content

Commit 02b1557

Browse files
Fix UnitTestRunner leaking some test class instances by @Youssef1313 in #5715 (backport to rel/3.9) (#5724)
Co-authored-by: Youssef1313 <[email protected]>
1 parent 6dc4d8e commit 02b1557

File tree

1 file changed

+21
-24
lines changed

1 file changed

+21
-24
lines changed

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

Lines changed: 21 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ namespace Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution;
2222
/// </summary>
2323
internal sealed class UnitTestRunner : MarshalByRefObject
2424
{
25-
private readonly ConcurrentDictionary<string, TestMethodInfo> _fixtureTests = new();
25+
private readonly ConcurrentDictionary<string, TestAssemblyInfo> _assemblyFixtureTests = new();
26+
private readonly ConcurrentDictionary<string, TestClassInfo> _classFixtureTests = new();
2627
private readonly TypeCache _typeCache;
2728
private readonly ReflectHelper _reflectHelper;
2829
private readonly ClassCleanupManager _classCleanupManager;
@@ -92,33 +93,29 @@ internal FixtureTestResult GetFixtureTestResult(TestMethod testMethod, string fi
9293
{
9394
// For the fixture methods, we need to return the appropriate result.
9495
// Get matching testMethodInfo from the cache and return UnitTestOutcome for the fixture test.
95-
if (_fixtureTests.TryGetValue(testMethod.AssemblyName + testMethod.FullClassName, out TestMethodInfo? testMethodInfo))
96+
if (fixtureType is Constants.ClassInitializeFixtureTrait or Constants.ClassCleanupFixtureTrait &&
97+
_classFixtureTests.TryGetValue(testMethod.AssemblyName + testMethod.FullClassName, out TestClassInfo? testClassInfo))
9698
{
97-
if (fixtureType == Constants.ClassInitializeFixtureTrait)
99+
UnitTestOutcome outcome = fixtureType switch
98100
{
99-
return testMethodInfo.Parent.IsClassInitializeExecuted
100-
? new(true, GetOutcome(testMethodInfo.Parent.ClassInitializationException))
101-
: new(true, UnitTestOutcome.Inconclusive);
102-
}
101+
Constants.ClassInitializeFixtureTrait => testClassInfo.IsClassInitializeExecuted ? GetOutcome(testClassInfo.ClassInitializationException) : UnitTestOutcome.Inconclusive,
102+
Constants.ClassCleanupFixtureTrait => testClassInfo.IsClassCleanupExecuted ? GetOutcome(testClassInfo.ClassCleanupException) : UnitTestOutcome.Inconclusive,
103+
_ => throw ApplicationStateGuard.Unreachable(),
104+
};
103105

104-
if (fixtureType == Constants.ClassCleanupFixtureTrait)
105-
{
106-
return testMethodInfo.Parent.IsClassInitializeExecuted
107-
? new(true, GetOutcome(testMethodInfo.Parent.ClassCleanupException))
108-
: new(true, UnitTestOutcome.Inconclusive);
109-
}
106+
return new FixtureTestResult(true, outcome);
110107
}
111-
112-
if (_fixtureTests.TryGetValue(testMethod.AssemblyName, out testMethodInfo))
108+
else if (fixtureType is Constants.AssemblyInitializeFixtureTrait or Constants.AssemblyCleanupFixtureTrait &&
109+
_assemblyFixtureTests.TryGetValue(testMethod.AssemblyName, out TestAssemblyInfo? testAssemblyInfo))
113110
{
114-
if (fixtureType == Constants.AssemblyInitializeFixtureTrait)
111+
Exception? exception = fixtureType switch
115112
{
116-
return new(true, GetOutcome(testMethodInfo.Parent.Parent.AssemblyInitializationException));
117-
}
118-
else if (fixtureType == Constants.AssemblyCleanupFixtureTrait)
119-
{
120-
return new(true, GetOutcome(testMethodInfo.Parent.Parent.AssemblyCleanupException));
121-
}
113+
Constants.AssemblyInitializeFixtureTrait => testAssemblyInfo.AssemblyInitializationException,
114+
Constants.AssemblyCleanupFixtureTrait => testAssemblyInfo.AssemblyCleanupException,
115+
_ => throw ApplicationStateGuard.Unreachable(),
116+
};
117+
118+
return new(true, GetOutcome(exception));
122119
}
123120

124121
return new(false, UnitTestOutcome.Inconclusive);
@@ -165,8 +162,8 @@ internal async Task<TestResult[]> RunSingleTestAsync(TestMethod testMethod, IDic
165162
DebugEx.Assert(testMethodInfo is not null, "testMethodInfo should not be null.");
166163

167164
// Keep track of all non-runnable methods so that we can return the appropriate result at the end.
168-
_fixtureTests.TryAdd(testMethod.AssemblyName, testMethodInfo);
169-
_fixtureTests.TryAdd(testMethod.AssemblyName + testMethod.FullClassName, testMethodInfo);
165+
_assemblyFixtureTests.TryAdd(testMethod.AssemblyName, testMethodInfo.Parent.Parent);
166+
_classFixtureTests.TryAdd(testMethod.AssemblyName + testMethod.FullClassName, testMethodInfo.Parent);
170167

171168
ITestContext testContextForAssemblyInit = PlatformServiceProvider.Instance.GetTestContext(testMethod, writer, properties, messageLogger, testContextForTestExecution.Context.CurrentTestOutcome);
172169

0 commit comments

Comments
 (0)