/
ParallelTestClassRunner.cs
64 lines (53 loc) · 3.04 KB
/
ParallelTestClassRunner.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
using System.Reflection;
using Xunit;
using Xunit.Abstractions;
using Xunit.Sdk;
namespace Meziantou.Xunit;
public class ParallelTestClassRunner : XunitTestClassRunner
{
public ParallelTestClassRunner(ITestClass testClass, IReflectionTypeInfo @class, IEnumerable<IXunitTestCase> testCases, IMessageSink diagnosticMessageSink, IMessageBus messageBus, ITestCaseOrderer testCaseOrderer, ExceptionAggregator aggregator, CancellationTokenSource cancellationTokenSource, IDictionary<Type, object> collectionFixtureMappings)
: base(testClass, @class, testCases, diagnosticMessageSink, messageBus, testCaseOrderer, aggregator, cancellationTokenSource, collectionFixtureMappings)
{
}
// This method has been slightly modified from the original implementation to run tests in parallel
// https://github.com/xunit/xunit/blob/2.4.2/src/xunit.execution/Sdk/Frameworks/Runners/TestClassRunner.cs#L194-L219
protected override async Task<RunSummary> RunTestMethodsAsync()
{
var disableParallelization = TestClass.Class.GetCustomAttributes(typeof(DisableParallelizationAttribute)).Any()
|| TestClass.Class.GetCustomAttributes(typeof(CollectionAttribute)).Any();
if (disableParallelization)
return await base.RunTestMethodsAsync().ConfigureAwait(false);
var summary = new RunSummary();
IEnumerable<IXunitTestCase> orderedTestCases;
try
{
orderedTestCases = TestCaseOrderer.OrderTestCases(TestCases);
}
catch (Exception ex)
{
var innerEx = Unwrap(ex);
DiagnosticMessageSink.OnMessage(new DiagnosticMessage($"Test case orderer '{TestCaseOrderer.GetType().FullName}' threw '{innerEx.GetType().FullName}' during ordering: {innerEx.Message}{Environment.NewLine}{innerEx.StackTrace}"));
orderedTestCases = TestCases.ToList();
}
var constructorArguments = CreateTestClassConstructorArguments();
var methodGroups = orderedTestCases.GroupBy(tc => tc.TestMethod, TestMethodComparer.Instance);
var methodTasks = methodGroups.Select(m => RunTestMethodAsync(m.Key, (IReflectionMethodInfo)m.Key.Method, m, constructorArguments));
var methodSummaries = await Task.WhenAll(methodTasks).ConfigureAwait(false);
foreach (var methodSummary in methodSummaries)
{
summary.Aggregate(methodSummary);
}
return summary;
}
protected override Task<RunSummary> RunTestMethodAsync(ITestMethod testMethod, IReflectionMethodInfo method, IEnumerable<IXunitTestCase> testCases, object[] constructorArguments)
=> new ParallelTestMethodRunner(testMethod, Class, method, testCases, DiagnosticMessageSink, MessageBus, new ExceptionAggregator(Aggregator), CancellationTokenSource, constructorArguments).RunAsync();
private static Exception Unwrap(Exception ex)
{
while (true)
{
if (ex is not TargetInvocationException tiex || tiex.InnerException == null)
return ex;
ex = tiex.InnerException;
}
}
}