Skip to content

Commit 84583c5

Browse files
authoredJun 21, 2024··
ClassCleanup are not executed if testclass is ignored (#3142)
1 parent a25e08a commit 84583c5

File tree

2 files changed

+136
-8
lines changed

2 files changed

+136
-8
lines changed
 

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

+10-8
Original file line numberDiff line numberDiff line change
@@ -476,22 +476,24 @@ internal void ExecuteClassCleanup()
476476
lock (_testClassExecuteSyncObject)
477477
{
478478
if (IsClassCleanupExecuted
479+
// If there is a ClassInitialize method and it has not been executed, then we should not execute ClassCleanup
479480
|| (!IsClassInitializeExecuted && ClassInitializeMethod is not null))
480481
{
481482
return;
482483
}
483484

484485
try
485486
{
486-
classCleanupMethod = ClassCleanupMethod;
487-
ClassCleanupException = classCleanupMethod is not null
488-
? InvokeCleanupMethod(classCleanupMethod, BaseClassCleanupMethodsStack.Count)
489-
: null;
490-
var baseClassCleanupQueue = new Queue<MethodInfo>(BaseClassCleanupMethodsStack);
491-
while (baseClassCleanupQueue.Count > 0 && ClassCleanupException is null)
487+
IEnumerable<MethodInfo> cleanupMethods = (ClassCleanupMethod is null ? Array.Empty<MethodInfo>() : [ClassCleanupMethod]).Union(BaseClassCleanupMethodsStack);
488+
var classCleanupQueue = new Queue<MethodInfo>(cleanupMethods);
489+
490+
while (classCleanupQueue.Count > 0 && ClassCleanupException is null)
492491
{
493-
classCleanupMethod = baseClassCleanupQueue.Dequeue();
494-
ClassCleanupException = InvokeCleanupMethod(classCleanupMethod, baseClassCleanupQueue.Count);
492+
classCleanupMethod = classCleanupQueue.Dequeue();
493+
if (!ReflectHelper.Instance.IsNonDerivedAttributeDefined<IgnoreAttribute>(classCleanupMethod.DeclaringType!, false))
494+
{
495+
ClassCleanupException = InvokeCleanupMethod(classCleanupMethod, classCleanupQueue.Count);
496+
}
495497
}
496498

497499
IsClassCleanupExecuted = ClassCleanupException is null;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
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 Microsoft.Testing.Platform.Acceptance.IntegrationTests;
5+
using Microsoft.Testing.Platform.Acceptance.IntegrationTests.Helpers;
6+
7+
namespace MSTest.Acceptance.IntegrationTests;
8+
9+
[TestGroup]
10+
public sealed class IgnoreTests : AcceptanceTestBase
11+
{
12+
private readonly TestAssetFixture _testAssetFixture;
13+
14+
public IgnoreTests(ITestExecutionContext testExecutionContext, TestAssetFixture testAssetFixture)
15+
: base(testExecutionContext)
16+
{
17+
_testAssetFixture = testAssetFixture;
18+
}
19+
20+
public async Task ClassCleanup_Inheritance_WhenClassIsSkipped()
21+
{
22+
var testHost = TestHost.LocateFrom(_testAssetFixture.ProjectPath, TestAssetFixture.ProjectName, TargetFrameworks.NetCurrent.Arguments);
23+
TestHostResult testHostResult = await testHost.ExecuteAsync("--settings my.runsettings");
24+
25+
// Assert
26+
testHostResult.AssertExitCodeIs(0);
27+
testHostResult.AssertOutputContains("Passed! - Failed: 0, Passed: 1, Skipped: 1, Total: 2");
28+
29+
testHostResult.AssertOutputContains("SubClass.Method");
30+
testHostResult.AssertOutputContains("SubClass.ClassCleanup");
31+
}
32+
33+
[TestFixture(TestFixtureSharingStrategy.PerTestGroup)]
34+
public sealed class TestAssetFixture(AcceptanceFixture acceptanceFixture) : TestAssetFixtureBase(acceptanceFixture.NuGetGlobalPackagesFolder)
35+
{
36+
public const string ProjectName = "TestIgnore";
37+
38+
public string ProjectPath => GetAssetPath(ProjectName);
39+
40+
public override IEnumerable<(string ID, string Name, string Code)> GetAssetsToGenerate()
41+
{
42+
yield return (ProjectName, ProjectName,
43+
SourceCode
44+
.PatchTargetFrameworks(TargetFrameworks.NetCurrent)
45+
.PatchCodeWithReplace("$MSTestVersion$", MSTestVersion));
46+
}
47+
48+
private const string SourceCode = """
49+
#file TestIgnore.csproj
50+
<Project Sdk="Microsoft.NET.Sdk">
51+
52+
<PropertyGroup>
53+
<OutputType>Exe</OutputType>
54+
<EnableMSTestRunner>true</EnableMSTestRunner>
55+
<TargetFrameworks>$TargetFrameworks$</TargetFrameworks>
56+
</PropertyGroup>
57+
58+
<ItemGroup>
59+
<PackageReference Include="MSTest.TestAdapter" Version="$MSTestVersion$" />
60+
<PackageReference Include="MSTest.TestFramework" Version="$MSTestVersion$" />
61+
</ItemGroup>
62+
63+
<ItemGroup>
64+
<None Update="*.runsettings">
65+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
66+
</None>
67+
</ItemGroup>
68+
69+
</Project>
70+
71+
#file my.runsettings
72+
<RunSettings>
73+
<MSTest>
74+
<CaptureTraceOutput>false</CaptureTraceOutput>
75+
</MSTest>
76+
</RunSettings>
77+
78+
#file UnitTest1.cs
79+
using System;
80+
using System.Threading.Tasks;
81+
using Microsoft.VisualStudio.TestTools.UnitTesting;
82+
83+
[Ignore]
84+
[TestClass]
85+
public class UnitTest1
86+
{
87+
[ClassCleanup]
88+
public static void ClassCleanup()
89+
=> throw new InvalidOperationException("ClassCleanup should not be called");
90+
91+
[TestMethod]
92+
public void Method()
93+
=> throw new InvalidOperationException("Test method should not be called");
94+
}
95+
96+
[TestClass]
97+
public class BaseClass
98+
{
99+
[ClassCleanup]
100+
public static void BaseClassCleanup()
101+
=> Console.WriteLine("BaseClass.ClassCleanup");
102+
}
103+
104+
[Ignore]
105+
[TestClass]
106+
public class IntermediateClass : BaseClass
107+
{
108+
[ClassCleanup]
109+
public static void IntermediateClassCleanup()
110+
=> throw new InvalidOperationException("IntermediateClass.ClassCleanup should not be called");
111+
}
112+
113+
[TestClass]
114+
public class SubClass : IntermediateClass
115+
{
116+
[ClassCleanup]
117+
public static void SubClassCleanup()
118+
=> Console.WriteLine("SubClass.ClassCleanup");
119+
120+
[TestMethod]
121+
public void Method()
122+
=> Console.WriteLine("SubClass.Method");
123+
}
124+
""";
125+
}
126+
}

0 commit comments

Comments
 (0)
Please sign in to comment.