Skip to content

Commit 862f9d5

Browse files
authored
Remove ConsiderFixturesAsSpecialTests (#7189)
1 parent e162620 commit 862f9d5

File tree

10 files changed

+5
-449
lines changed

10 files changed

+5
-449
lines changed

src/Adapter/MSTestAdapter.PlatformServices/Discovery/AssemblyEnumerator.cs

Lines changed: 2 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@
77
using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution;
88
using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Helpers;
99
using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel;
10-
using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices;
11-
using Microsoft.VisualStudio.TestPlatform.ObjectModel;
1210
using Microsoft.VisualStudio.TestTools.UnitTesting;
1311
using Microsoft.VisualStudio.TestTools.UnitTesting.Internal;
1412

@@ -69,8 +67,6 @@ internal AssemblyEnumerationResult EnumerateAssembly(string assemblyFileName)
6967
List<string> warnings = [];
7068
DebugEx.Assert(!StringEx.IsNullOrWhiteSpace(assemblyFileName), "Invalid assembly file name.");
7169
var tests = new List<UnitTestElement>();
72-
// Contains list of assembly/class names for which we have already added fixture tests.
73-
var fixturesTests = new HashSet<string>();
7470

7571
Assembly assembly = PlatformServiceProvider.Instance.FileOperations.LoadAssembly(assemblyFileName);
7672

@@ -94,7 +90,7 @@ internal AssemblyEnumerationResult EnumerateAssembly(string assemblyFileName)
9490
foreach (Type type in types)
9591
{
9692
List<UnitTestElement> testsInType = DiscoverTestsInType(assemblyFileName, type, warnings, discoverInternals,
97-
dataSourcesUnfoldingStrategy, fixturesTests);
93+
dataSourcesUnfoldingStrategy);
9894
tests.AddRange(testsInType);
9995
}
10096

@@ -154,8 +150,7 @@ private List<UnitTestElement> DiscoverTestsInType(
154150
Type type,
155151
List<string> warningMessages,
156152
bool discoverInternals,
157-
TestDataSourceUnfoldingStrategy dataSourcesUnfoldingStrategy,
158-
HashSet<string> fixturesTests)
153+
TestDataSourceUnfoldingStrategy dataSourcesUnfoldingStrategy)
159154
{
160155
string? typeFullName = null;
161156
var tests = new List<UnitTestElement>();
@@ -172,12 +167,6 @@ private List<UnitTestElement> DiscoverTestsInType(
172167
{
173168
if (_typeCache.GetTestMethodInfoForDiscovery(test.TestMethod) is { } testMethodInfo)
174169
{
175-
// Add fixture tests like AssemblyInitialize, AssemblyCleanup, ClassInitialize, ClassCleanup.
176-
if (MSTestSettings.CurrentSettings.ConsiderFixturesAsSpecialTests)
177-
{
178-
AddFixtureTests(testMethodInfo, tests, fixturesTests);
179-
}
180-
181170
if (TryUnfoldITestDataSources(test, testMethodInfo, dataSourcesUnfoldingStrategy, tests))
182171
{
183172
continue;
@@ -200,88 +189,6 @@ private List<UnitTestElement> DiscoverTestsInType(
200189
return tests;
201190
}
202191

203-
private static void AddFixtureTests(DiscoveryTestMethodInfo testMethodInfo, List<UnitTestElement> tests, HashSet<string> fixtureTests)
204-
{
205-
string assemblyName = testMethodInfo.Parent.Parent.Assembly.GetName().Name!;
206-
string assemblyLocation = testMethodInfo.Parent.Parent.Assembly.Location;
207-
string classFullName = testMethodInfo.Parent.ClassType.FullName!;
208-
209-
// Check if fixtures for this assembly has already been added.
210-
if (!fixtureTests.Contains(assemblyLocation))
211-
{
212-
_ = fixtureTests.Add(assemblyLocation);
213-
214-
// Add AssemblyInitialize and AssemblyCleanup fixture tests if they exist.
215-
if (testMethodInfo.Parent.Parent.AssemblyInitializeMethod is not null)
216-
{
217-
tests.Add(GetAssemblyFixtureTest(testMethodInfo.Parent.Parent.AssemblyInitializeMethod, assemblyName,
218-
classFullName, assemblyLocation, EngineConstants.AssemblyInitializeFixtureTrait));
219-
}
220-
221-
if (testMethodInfo.Parent.Parent.AssemblyCleanupMethod is not null)
222-
{
223-
tests.Add(GetAssemblyFixtureTest(testMethodInfo.Parent.Parent.AssemblyCleanupMethod, assemblyName,
224-
classFullName, assemblyLocation, EngineConstants.AssemblyCleanupFixtureTrait));
225-
}
226-
}
227-
228-
// Check if fixtures for this class has already been added.
229-
if (!fixtureTests.Contains(assemblyLocation + classFullName))
230-
{
231-
_ = fixtureTests.Add(assemblyLocation + classFullName);
232-
233-
// Add ClassInitialize and ClassCleanup fixture tests if they exist.
234-
if (testMethodInfo.Parent.ClassInitializeMethod is not null)
235-
{
236-
tests.Add(GetClassFixtureTest(testMethodInfo.Parent.ClassInitializeMethod, classFullName,
237-
assemblyLocation, EngineConstants.ClassInitializeFixtureTrait));
238-
}
239-
240-
if (testMethodInfo.Parent.ClassCleanupMethod is not null)
241-
{
242-
tests.Add(GetClassFixtureTest(testMethodInfo.Parent.ClassCleanupMethod, classFullName,
243-
assemblyLocation, EngineConstants.ClassCleanupFixtureTrait));
244-
}
245-
}
246-
247-
static UnitTestElement GetAssemblyFixtureTest(MethodInfo methodInfo, string assemblyName, string classFullName,
248-
string assemblyLocation, string fixtureType)
249-
{
250-
string methodName = GetMethodName(methodInfo);
251-
string[] hierarchy = [null!, assemblyName, EngineConstants.AssemblyFixturesHierarchyClassName, methodName];
252-
return GetFixtureTest(classFullName, assemblyLocation, fixtureType, methodName, hierarchy, methodInfo);
253-
}
254-
255-
static UnitTestElement GetClassFixtureTest(MethodInfo methodInfo, string classFullName,
256-
string assemblyLocation, string fixtureType)
257-
{
258-
string methodName = GetMethodName(methodInfo);
259-
string[] hierarchy = [null!, classFullName, methodName];
260-
return GetFixtureTest(classFullName, assemblyLocation, fixtureType, methodName, hierarchy, methodInfo);
261-
}
262-
263-
static string GetMethodName(MethodInfo methodInfo)
264-
{
265-
ParameterInfo[] args = methodInfo.GetParameters();
266-
return args.Length > 0
267-
? $"{methodInfo.Name}({string.Join(',', args.Select(a => a.ParameterType.FullName))})"
268-
: methodInfo.Name;
269-
}
270-
271-
static UnitTestElement GetFixtureTest(string classFullName, string assemblyLocation, string fixtureType, string methodName, string[] hierarchy, MethodInfo methodInfo)
272-
{
273-
string displayName = $"[{fixtureType}] {methodName}";
274-
var method = new TestMethod(classFullName, methodName, hierarchy, methodName, classFullName, assemblyLocation, displayName, null)
275-
{
276-
MethodInfo = methodInfo,
277-
};
278-
return new UnitTestElement(method)
279-
{
280-
Traits = [new Trait(EngineConstants.FixturesTestTrait, fixtureType)],
281-
};
282-
}
283-
}
284-
285192
private static bool TryUnfoldITestDataSources(UnitTestElement test, DiscoveryTestMethodInfo testMethodInfo, TestDataSourceUnfoldingStrategy dataSourcesUnfoldingStrategy, List<UnitTestElement> tests)
286193
{
287194
// It should always be `true`, but if any part of the chain is obsolete; it might not contain those.

src/Adapter/MSTestAdapter.PlatformServices/Discovery/UnitTestDiscoverer.cs

Lines changed: 0 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,7 @@
33

44
using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Discovery;
55
using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel;
6-
using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices;
76
using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Interface;
8-
using Microsoft.VisualStudio.TestPlatform.ObjectModel;
97
using Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter;
108
using Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging;
119
using Microsoft.VisualStudio.TestTools.UnitTesting;
@@ -102,9 +100,6 @@ internal virtual void DiscoverTestsInSource(
102100

103101
internal void SendTestCases(IEnumerable<UnitTestElement> testElements, ITestCaseDiscoverySink discoverySink, IDiscoveryContext? discoveryContext, IMessageLogger logger)
104102
{
105-
bool hasAnyRunnableTests = false;
106-
var fixtureTests = new List<TestCase>();
107-
108103
// Get filter expression and skip discovery in case filter expression has parsing error.
109104
ITestCaseFilterExpression? filterExpression = _testMethodFilter.GetFilterExpression(discoveryContext, logger, out bool filterHasError);
110105
if (filterHasError)
@@ -115,38 +110,14 @@ internal void SendTestCases(IEnumerable<UnitTestElement> testElements, ITestCase
115110
foreach (UnitTestElement testElement in testElements)
116111
{
117112
var testCase = testElement.ToTestCase();
118-
bool hasFixtureTraits = testElement.Traits?.Any(t => t.Name == EngineConstants.FixturesTestTrait) == true;
119113

120114
// Filter tests based on test case filters
121115
if (filterExpression != null && !filterExpression.MatchTestCase(testCase, p => _testMethodFilter.PropertyValueProvider(testCase, p)))
122116
{
123-
// If test is a fixture test, add it to the list of fixture tests.
124-
if (hasFixtureTraits)
125-
{
126-
fixtureTests.Add(testCase);
127-
}
128-
129117
continue;
130118
}
131119

132-
if (!hasAnyRunnableTests)
133-
{
134-
hasAnyRunnableTests = !hasFixtureTraits;
135-
}
136-
137120
discoverySink.SendTestCase(testCase);
138121
}
139-
140-
// If there are runnable tests, then add all fixture tests to the discovery sink.
141-
// Scenarios:
142-
// 1. Execute only a fixture test => In this case, we do not need to track any other fixture tests. Selected fixture test will be tracked as will be marked as skipped.
143-
// 2. Execute a runnable test => In this case, case add all fixture tests. We will update status of only those fixtures which are triggered by the selected test.
144-
if (hasAnyRunnableTests)
145-
{
146-
foreach (TestCase testCase in fixtureTests)
147-
{
148-
discoverySink.SendTestCase(testCase);
149-
}
150-
}
151122
}
152123
}

src/Adapter/MSTestAdapter.PlatformServices/Execution/TestExecutionManager.cs

Lines changed: 0 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -443,9 +443,6 @@ private async Task ExecuteTestsWithTestRunnerAsync(
443443
UnitTestRunner testRunner,
444444
bool usesAppDomains)
445445
{
446-
bool hasAnyRunnableTests = false;
447-
List<TestCase>? fixtureTests = null;
448-
449446
IEnumerable<TestCase> orderedTests = MSTestSettings.CurrentSettings.OrderTestsByNameInClass
450447
? tests.OrderBy(t => t.GetManagedType()).ThenBy(t => t.GetManagedMethod())
451448
: tests;
@@ -464,15 +461,6 @@ private async Task ExecuteTestsWithTestRunnerAsync(
464461
break;
465462
}
466463

467-
// If it is a fixture test, add it to the list of fixture tests and do not execute it.
468-
// It is executed by test itself.
469-
if (currentTest.Traits.Any(t => t.Name == EngineConstants.FixturesTestTrait))
470-
{
471-
(fixtureTests ??= []).Add(currentTest);
472-
continue;
473-
}
474-
475-
hasAnyRunnableTests = true;
476464
UnitTestElement unitTestElement = currentTest.ToUnitTestElementWithUpdatedSource(source);
477465

478466
testExecutionRecorder.RecordStart(currentTest);
@@ -509,44 +497,6 @@ private async Task ExecuteTestsWithTestRunnerAsync(
509497

510498
SendTestResults(currentTest, unitTestResult, startTime, endTime, testExecutionRecorder);
511499
}
512-
513-
// Once all tests have been executed, update the status of fixture tests.
514-
if (fixtureTests is null)
515-
{
516-
return;
517-
}
518-
519-
foreach (TestCase currentTest in fixtureTests)
520-
{
521-
_testRunCancellationToken?.ThrowIfCancellationRequested();
522-
523-
testExecutionRecorder.RecordStart(currentTest);
524-
525-
// If there were only fixture tests, send an inconclusive result.
526-
if (!hasAnyRunnableTests)
527-
{
528-
var result = new TestTools.UnitTesting.TestResult
529-
{
530-
Outcome = TestTools.UnitTesting.UnitTestOutcome.Inconclusive,
531-
};
532-
533-
SendTestResults(currentTest, [result], DateTimeOffset.Now, DateTimeOffset.Now, testExecutionRecorder);
534-
continue;
535-
}
536-
537-
Trait trait = currentTest.Traits.First(t => t.Name == EngineConstants.FixturesTestTrait);
538-
UnitTestElement unitTestElement = currentTest.ToUnitTestElementWithUpdatedSource(source);
539-
FixtureTestResult fixtureTestResult = testRunner.GetFixtureTestResult(unitTestElement.TestMethod, trait.Value);
540-
541-
if (fixtureTestResult.IsExecuted)
542-
{
543-
var result = new TestTools.UnitTesting.TestResult
544-
{
545-
Outcome = fixtureTestResult.Outcome,
546-
};
547-
SendTestResults(currentTest, [result], DateTimeOffset.Now, DateTimeOffset.Now, testExecutionRecorder);
548-
}
549-
}
550500
}
551501

552502
/// <summary>

src/Adapter/MSTestAdapter.PlatformServices/Execution/UnitTestRunner.cs

Lines changed: 0 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,6 @@ namespace Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution;
2323
/// </summary>
2424
internal sealed class UnitTestRunner : MarshalByRefObject
2525
{
26-
private readonly ConcurrentDictionary<string, TestAssemblyInfo> _assemblyFixtureTests = new();
27-
private readonly ConcurrentDictionary<string, TestClassInfo> _classFixtureTests = new();
2826
private readonly TypeCache _typeCache;
2927
private readonly ClassCleanupManager _classCleanupManager;
3028

@@ -81,41 +79,6 @@ public void Cancel()
8179
#endif
8280
public override object InitializeLifetimeService() => null!;
8381

84-
internal FixtureTestResult GetFixtureTestResult(TestMethod testMethod, string fixtureType)
85-
{
86-
// For the fixture methods, we need to return the appropriate result.
87-
// Get matching testMethodInfo from the cache and return UnitTestOutcome for the fixture test.
88-
if (fixtureType is EngineConstants.ClassInitializeFixtureTrait or EngineConstants.ClassCleanupFixtureTrait &&
89-
_classFixtureTests.TryGetValue(testMethod.AssemblyName + testMethod.FullClassName, out TestClassInfo? testClassInfo))
90-
{
91-
UnitTestOutcome outcome = fixtureType switch
92-
{
93-
EngineConstants.ClassInitializeFixtureTrait => testClassInfo.IsClassInitializeExecuted ? GetOutcome(testClassInfo.ClassInitializationException) : UnitTestOutcome.Inconclusive,
94-
EngineConstants.ClassCleanupFixtureTrait => testClassInfo.IsClassCleanupExecuted ? GetOutcome(testClassInfo.ClassCleanupException) : UnitTestOutcome.Inconclusive,
95-
_ => throw ApplicationStateGuard.Unreachable(),
96-
};
97-
98-
return new FixtureTestResult(true, outcome);
99-
}
100-
else if (fixtureType is EngineConstants.AssemblyInitializeFixtureTrait or EngineConstants.AssemblyCleanupFixtureTrait &&
101-
_assemblyFixtureTests.TryGetValue(testMethod.AssemblyName, out TestAssemblyInfo? testAssemblyInfo))
102-
{
103-
Exception? exception = fixtureType switch
104-
{
105-
EngineConstants.AssemblyInitializeFixtureTrait => testAssemblyInfo.AssemblyInitializationException,
106-
EngineConstants.AssemblyCleanupFixtureTrait => testAssemblyInfo.AssemblyCleanupException,
107-
_ => throw ApplicationStateGuard.Unreachable(),
108-
};
109-
110-
return new(true, GetOutcome(exception));
111-
}
112-
113-
return new(false, UnitTestOutcome.Inconclusive);
114-
115-
// Local functions
116-
static UnitTestOutcome GetOutcome(Exception? exception) => exception == null ? UnitTestOutcome.Passed : UnitTestOutcome.Failed;
117-
}
118-
11982
// Task cannot cross app domains.
12083
// For now, TestExecutionManager will call this sync method which is hacky.
12184
// If we removed AppDomains in v4, we should use the async method and remove this one.
@@ -158,13 +121,6 @@ internal async Task<TestResult[]> RunSingleTestAsync(TestMethod testMethod, IDic
158121
{
159122
DebugEx.Assert(testMethodInfo is not null, "testMethodInfo should not be null.");
160123

161-
// Keep track of all non-runnable methods so that we can return the appropriate result at the end.
162-
if (MSTestSettings.CurrentSettings.ConsiderFixturesAsSpecialTests)
163-
{
164-
_assemblyFixtureTests.TryAdd(testMethod.AssemblyName, testMethodInfo.Parent.Parent);
165-
_classFixtureTests.TryAdd(testMethod.AssemblyName + testMethod.FullClassName, testMethodInfo.Parent);
166-
}
167-
168124
testContextForAssemblyInit = PlatformServiceProvider.Instance.GetTestContext(testMethod: null, null, testContextProperties, messageLogger, testContextForTestExecution.Context.CurrentTestOutcome);
169125

170126
TestResult assemblyInitializeResult = await RunAssemblyInitializeIfNeededAsync(testMethodInfo, testContextForAssemblyInit).ConfigureAwait(false);

0 commit comments

Comments
 (0)