Skip to content

Commit 37d6b05

Browse files
authored
Fix cleanup inheritance calls (#1475)
1 parent 8c649fd commit 37d6b05

File tree

4 files changed

+379
-15
lines changed

4 files changed

+379
-15
lines changed

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

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010

1111
using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Extensions;
1212
using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel;
13-
using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Interface;
1413
using Microsoft.VisualStudio.TestTools.UnitTesting;
1514

1615
using ObjectModelUnitTestOutcome = Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestOutcome;
@@ -155,19 +154,19 @@ public bool HasExecutableCleanupMethod
155154
{
156155
get
157156
{
158-
if (BaseClassCleanupMethodsStack.Any())
157+
// If class has a cleanup method, then it is executable.
158+
if (ClassCleanupMethod is not null)
159159
{
160-
// If any base cleanups were pushed to the stack we need to run them
161160
return true;
162161
}
163162

164-
// If no class cleanup, then continue with the next one.
165-
if (ClassCleanupMethod == null)
163+
// Otherwise, if any base cleanups were pushed to the stack we need to run them
164+
if (BaseClassCleanupMethodsStack.Any())
166165
{
167-
return false;
166+
return true;
168167
}
169168

170-
return true;
169+
return false;
171170
}
172171
}
173172

src/Adapter/MSTest.TestAdapter/Helpers/ReflectHelper.cs

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
11
// Copyright (c) Microsoft Corporation. All rights reserved.
22
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
33

4-
#nullable enable
5-
64
using System;
75
using System.Collections.Generic;
8-
using System.Diagnostics;
96
using System.Diagnostics.CodeAnalysis;
107
using System.Globalization;
118
using System.Linq;
@@ -487,14 +484,30 @@ internal virtual TAttribute[] GetCustomAttributes<TAttribute>(MemberInfo attribu
487484
/// <returns>Returns <see cref="ClassCleanupBehavior"/> if provided, otherwise <c>null</c>.</returns>
488485
internal virtual ClassCleanupBehavior? GetClassCleanupBehavior(TestClassInfo classInfo)
489486
{
490-
if (classInfo.ClassCleanupMethod == null)
487+
if (!classInfo.HasExecutableCleanupMethod)
491488
{
492489
return null;
493490
}
494491

495-
var sequencingAttribute = GetCustomAttributes<ClassCleanupAttribute>(classInfo.ClassCleanupMethod, true)?.FirstOrDefault();
492+
var cleanupBehaviors =
493+
new HashSet<ClassCleanupBehavior?>(
494+
classInfo.BaseClassCleanupMethodsStack
495+
.Select(x => x.GetCustomAttribute<ClassCleanupAttribute>(true)?.CleanupBehavior))
496+
{
497+
classInfo.ClassCleanupMethod?.GetCustomAttribute<ClassCleanupAttribute>(true)?.CleanupBehavior,
498+
};
499+
500+
if (cleanupBehaviors.Contains(ClassCleanupBehavior.EndOfClass))
501+
{
502+
return ClassCleanupBehavior.EndOfClass;
503+
}
496504

497-
return sequencingAttribute?.CleanupBehavior;
505+
if (cleanupBehaviors.Contains(ClassCleanupBehavior.EndOfAssembly))
506+
{
507+
return ClassCleanupBehavior.EndOfAssembly;
508+
}
509+
510+
return null;
498511
}
499512

500513
/// <summary>

test/E2ETests/Smoke.E2E.Tests/SuiteLifeCycleTests.cs

Lines changed: 126 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
33

44
using System;
5-
using System.Collections.Generic;
65
using System.Linq;
76

87
using FluentAssertions;
@@ -24,9 +23,134 @@ public void ValidateTestRunLifecycle_net462()
2423
ValidateTestRunLifecycle("net462");
2524
}
2625

26+
public void ValidateInheritanceBehavior()
27+
{
28+
InvokeVsTestForExecution(
29+
new[] { "net462\\" + Assembly },
30+
testCaseFilter: "FullyQualifiedName~LifecycleInheritance",
31+
targetFramework: "net462");
32+
33+
RunEventsHandler.PassedTests.Should().HaveCount(10);
34+
35+
var testMethod1 = RunEventsHandler.PassedTests.Single(x => x.TestCase.FullyQualifiedName.EndsWith("TestClassDerived_EndOfClass.TestMethod"));
36+
testMethod1.Messages[0].Text.Should().Be(
37+
"""
38+
Console: AssemblyInit was called
39+
TestClassBaseEndOfClass: ClassInitialize
40+
TestClassDerived_EndOfClass: TestMethod
41+
TestClassBaseEndOfClass: ClassCleanup
42+
43+
""");
44+
45+
var testMethod2 = RunEventsHandler.PassedTests.Single(x => x.TestCase.FullyQualifiedName.EndsWith("TestClassDerived_EndOfAssembly.TestMethod"));
46+
testMethod2.Messages[0].Text.Should().Be(
47+
"""
48+
TestClassBaseEndOfAssembly: ClassInitialize
49+
TestClassDerived_EndOfAssembly: TestMethod
50+
51+
""");
52+
53+
var testMethod3 = RunEventsHandler.PassedTests.Single(x => x.TestCase.FullyQualifiedName.EndsWith("TestClassDerivedEndOfClass_EndOfClassEndOfClass.TestMethod"));
54+
testMethod3.Messages[0].Text.Should().Be(
55+
"""
56+
TestClassBaseEndOfClass: ClassInitialize
57+
TestClassIntermediateEndOfClassBaseEndOfClass: ClassInitialize
58+
TestClassDerivedEndOfClass_EndOfClassEndOfClass: TestMethod
59+
TestClassDerivedEndOfClass_EndOfClassEndOfClass: ClassCleanup
60+
TestClassIntermediateEndOfClassBaseEndOfClass: ClassCleanup
61+
TestClassBaseEndOfClass: ClassCleanup
62+
63+
""");
64+
65+
var testMethod4 = RunEventsHandler.PassedTests.Single(x => x.TestCase.FullyQualifiedName.EndsWith("TestClassDerived_EndOfClassEndOfClass.TestMethod"));
66+
testMethod4.Messages[0].Text.Should().Be(
67+
"""
68+
TestClassBaseEndOfClass: ClassInitialize
69+
TestClassIntermediateEndOfClassBaseEndOfClass: ClassInitialize
70+
TestClassDerived_EndOfClassEndOfClass: TestMethod
71+
TestClassIntermediateEndOfClassBaseEndOfClass: ClassCleanup
72+
TestClassBaseEndOfClass: ClassCleanup
73+
74+
""");
75+
76+
var testMethod5 = RunEventsHandler.PassedTests.Single(x => x.TestCase.FullyQualifiedName.EndsWith("TestClassDerivedEndOfClass_EndOfClassEndOfAssembly.TestMethod"));
77+
testMethod5.Messages[0].Text.Should().Be(
78+
"""
79+
TestClassBaseEndOfAssembly: ClassInitialize
80+
TestClassIntermediateEndOfClassBaseEndOfAssembly: ClassInitialize
81+
TestClassDerivedEndOfClass_EndOfClassEndOfAssembly: TestMethod
82+
TestClassDerivedEndOfClass_EndOfClassEndOfAssembly: ClassCleanup
83+
TestClassIntermediateEndOfClassBaseEndOfAssembly: ClassCleanup
84+
TestClassBaseEndOfAssembly: ClassCleanup
85+
86+
""");
87+
88+
var testMethod6 = RunEventsHandler.PassedTests.Single(x => x.TestCase.FullyQualifiedName.EndsWith("TestClassDerived_EndOfClassEndOfAssembly.TestMethod"));
89+
testMethod6.Messages[0].Text.Should().Be(
90+
"""
91+
TestClassBaseEndOfAssembly: ClassInitialize
92+
TestClassIntermediateEndOfClassBaseEndOfAssembly: ClassInitialize
93+
TestClassDerived_EndOfClassEndOfAssembly: TestMethod
94+
TestClassIntermediateEndOfClassBaseEndOfAssembly: ClassCleanup
95+
TestClassBaseEndOfAssembly: ClassCleanup
96+
97+
""");
98+
99+
var testMethod7 = RunEventsHandler.PassedTests.Single(x => x.TestCase.FullyQualifiedName.EndsWith("TestClassDerivedEndOfClass_EndOfAssemblyEndOfClass.TestMethod"));
100+
testMethod7.Messages[0].Text.Should().Be(
101+
"""
102+
TestClassBaseEndOfClass: ClassInitialize
103+
TestClassIntermediateEndOfAssemblyBaseEndOfClass: ClassInitialize
104+
TestClassDerivedEndOfClass_EndOfAssemblyEndOfClass: TestMethod
105+
TestClassDerivedEndOfClass_EndOfAssemblyEndOfClass: ClassCleanup
106+
TestClassIntermediateEndOfAssemblyBaseEndOfClass: ClassCleanup
107+
TestClassBaseEndOfClass: ClassCleanup
108+
109+
""");
110+
111+
var testMethod8 = RunEventsHandler.PassedTests.Single(x => x.TestCase.FullyQualifiedName.EndsWith("TestClassDerived_EndOfAssemblyEndOfClass.TestMethod"));
112+
testMethod8.Messages[0].Text.Should().Be(
113+
"""
114+
TestClassBaseEndOfClass: ClassInitialize
115+
TestClassIntermediateEndOfAssemblyBaseEndOfClass: ClassInitialize
116+
TestClassDerived_EndOfAssemblyEndOfClass: TestMethod
117+
TestClassIntermediateEndOfAssemblyBaseEndOfClass: ClassCleanup
118+
TestClassBaseEndOfClass: ClassCleanup
119+
120+
""");
121+
122+
var testMethod9 = RunEventsHandler.PassedTests.Single(x => x.TestCase.FullyQualifiedName.EndsWith("TestClassDerivedEndOfClass_EndOfAssemblyEndOfAssembly.TestMethod"));
123+
testMethod9.Messages[0].Text.Should().Be(
124+
"""
125+
TestClassBaseEndOfAssembly: ClassInitialize
126+
TestClassIntermediateEndOfAssemblyBaseEndOfAssembly: ClassInitialize
127+
TestClassDerivedEndOfClass_EndOfAssemblyEndOfAssembly: TestMethod
128+
TestClassDerivedEndOfClass_EndOfAssemblyEndOfAssembly: ClassCleanup
129+
TestClassIntermediateEndOfAssemblyBaseEndOfAssembly: ClassCleanup
130+
TestClassBaseEndOfAssembly: ClassCleanup
131+
132+
""");
133+
134+
var testMethod10 = RunEventsHandler.PassedTests.Single(x => x.TestCase.FullyQualifiedName.EndsWith("TestClassDerived_EndOfAssemblyEndOfAssembly.TestMethod"));
135+
testMethod10.Messages[0].Text.Should().Be(
136+
"""
137+
TestClassBaseEndOfAssembly: ClassInitialize
138+
TestClassIntermediateEndOfAssemblyBaseEndOfAssembly: ClassInitialize
139+
TestClassDerived_EndOfAssemblyEndOfAssembly: TestMethod
140+
TestClassIntermediateEndOfAssemblyBaseEndOfAssembly: ClassCleanup
141+
TestClassBaseEndOfAssembly: ClassCleanup
142+
TestClassBaseEndOfAssembly: ClassCleanup
143+
Console: AssemblyCleanup was called
144+
145+
""");
146+
}
147+
27148
private void ValidateTestRunLifecycle(string targetFramework)
28149
{
29-
InvokeVsTestForExecution(new[] { targetFramework + "\\" + Assembly }, targetFramework: targetFramework);
150+
InvokeVsTestForExecution(
151+
new[] { targetFramework + "\\" + Assembly },
152+
testCaseFilter: "FullyQualifiedName~SuiteLifeCycleTestProject",
153+
targetFramework: targetFramework);
30154
RunEventsHandler.PassedTests.Should().HaveCount(27); // The inherit class tests are called twice.
31155

32156
var caseClassCleanup = RunEventsHandler.PassedTests.Single(x => x.TestCase.FullyQualifiedName.Contains("LifeCycleClassCleanup.TestMethod"));

0 commit comments

Comments
 (0)