Skip to content

Commit 74eb583

Browse files
committed
Added ability to sort test collections.
1 parent 226f186 commit 74eb583

6 files changed

Lines changed: 79 additions & 7 deletions

File tree

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
using System.Collections.Generic;
2+
using System.Linq;
3+
using Xunit.Abstractions;
4+
5+
namespace Xunit.Sdk
6+
{
7+
/// <summary>
8+
/// A class implements this interface to participate in ordering test collections
9+
/// for the test runner. Test collection orderers are applied using the
10+
/// <see cref="TestCollectionOrdererAttribute"/>, which can be applied at
11+
/// the assembly level.
12+
/// </summary>
13+
public interface ITestCollectionOrderer
14+
{
15+
/// <summary>
16+
/// Orders test collections for execution.
17+
/// </summary>
18+
/// <param name="testCollections">The test collections to be ordered.</param>
19+
/// <returns>The test collections in the order to be run.</returns>
20+
IEnumerable<IGrouping<ITestCollection, TTestCase>> OrderTestCollections<TTestCase>(IEnumerable<IGrouping<ITestCollection, TTestCase>> testCollections) where TTestCase : ITestCase;
21+
}
22+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
using System;
2+
3+
namespace Xunit
4+
{
5+
/// <summary>
6+
/// Used to decorate an assembly to allow
7+
/// the use a custom <see cref="T:Xunit.Sdk.ICollectionOrderer"/>.
8+
/// </summary>
9+
[AttributeUsage(AttributeTargets.Assembly, Inherited = true, AllowMultiple = false)]
10+
public sealed class TestCollectionOrdererAttribute : Attribute
11+
{
12+
/// <summary>
13+
/// Initializes a new instance of the <see cref="TestCollectionOrdererAttribute"/> class.
14+
/// </summary>
15+
/// <param name="ordererTypeName">The type name of the orderer class (that implements <see cref="T:Xunit.Sdk.ICollectionOrderer"/>).</param>
16+
/// <param name="ordererAssemblyName">The assembly that <paramref name="ordererTypeName"/> exists in.</param>
17+
public TestCollectionOrdererAttribute(string ordererTypeName, string ordererAssemblyName) { }
18+
}
19+
}

src/xunit.core/xunit.core.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@
5656
<Compile Include="CollectionBehavior.cs" />
5757
<Compile Include="CollectionBehaviorAttribute.cs" />
5858
<Compile Include="CollectionDefinitionAttribute.cs" />
59+
<Compile Include="Sdk\ITestCollectionOrderer.cs" />
60+
<Compile Include="TestCollectionOrdererAttribute.cs" />
5961
<Compile Include="FactAttribute.cs" />
6062
<Compile Include="IClassFixture.cs" />
6163
<Compile Include="ICollectionFixture.cs" />

src/xunit.execution/Sdk/ExtensibilityPointFactory.cs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,14 @@ public static ITestCaseOrderer GetTestCaseOrderer(Type ordererType)
7878
return Get<ITestCaseOrderer>(ordererType);
7979
}
8080

81+
/// <summary>
82+
/// Gets a test collection orderer.
83+
/// </summary>
84+
public static ITestCollectionOrderer GetTestCollectionOrderer(Type ordererType)
85+
{
86+
return Get<ITestCollectionOrderer>(ordererType);
87+
}
88+
8189
/// <summary>
8290
/// Gets a test case orderer, as specified in a reflected <see cref="TestCaseOrdererAttribute"/>.
8391
/// </summary>
@@ -93,6 +101,17 @@ public static ITestCaseOrderer GetTestCaseOrderer(IAttributeInfo testCaseOrderer
93101
return GetTestCaseOrderer(ordererType);
94102
}
95103

104+
105+
public static ITestCollectionOrderer GetTestCollectionOrderer(IAttributeInfo testCollectionOrdererAttribute)
106+
{
107+
var args = testCollectionOrdererAttribute.GetConstructorArguments().Cast<string>().ToList();
108+
var ordererType = Reflector.GetType(args[1], args[0]);
109+
if (ordererType == null)
110+
return null;
111+
112+
return GetTestCollectionOrderer(ordererType);
113+
}
114+
96115
/// <summary>
97116
/// Gets a trait discoverer.
98117
/// </summary>

src/xunit.execution/Sdk/Frameworks/Runners/TestAssemblyRunner.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,11 @@ public TestAssemblyRunner(IAssemblyInfo assemblyInfo,
6363
/// </summary>
6464
protected ITestCaseOrderer TestCaseOrderer { get; set; }
6565

66+
/// <summary>
67+
/// Gets or sets the test collection orderer that will be used to decide how to order test collections.
68+
/// </summary>
69+
protected ITestCollectionOrderer TestCollectionOrderer { get; set; }
70+
6671
/// <summary>
6772
/// Gets or sets the test cases to be run.
6873
/// </summary>

src/xunit.execution/Sdk/Frameworks/Runners/XunitTestAssemblyRunner.cs

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -92,20 +92,25 @@ protected override void OnAssemblyStarting()
9292
scheduler = GetTaskScheduler(maxParallelThreads);
9393

9494
var ordererAttribute = AssemblyInfo.GetCustomAttributes(typeof(TestCaseOrdererAttribute)).SingleOrDefault();
95-
if (ordererAttribute != null)
96-
TestCaseOrderer = ExtensibilityPointFactory.GetTestCaseOrderer(ordererAttribute);
95+
if (ordererAttribute != null) TestCaseOrderer = ExtensibilityPointFactory.GetTestCaseOrderer(ordererAttribute);
96+
97+
var collectionOrdererAttribute = AssemblyInfo.GetCustomAttributes(typeof(TestCollectionOrdererAttribute)).SingleOrDefault();
98+
if (collectionOrdererAttribute != null) TestCollectionOrderer = ExtensibilityPointFactory.GetTestCollectionOrderer(collectionOrdererAttribute);
9799
}
98100

99101
/// <inheritdoc/>
100102
protected override async Task<RunSummary> RunTestCollectionsAsync(IMessageBus messageBus, CancellationTokenSource cancellationTokenSource)
101103
{
102-
if (disableParallelization)
103-
return await base.RunTestCollectionsAsync(messageBus, cancellationTokenSource);
104-
var testCollections = TestCases.Cast<IXunitTestCase>()
105-
.GroupBy(tc => tc.TestCollection, TestCollectionComparer.Instance)
106-
.ToArray();
104+
if (disableParallelization) return await base.RunTestCollectionsAsync(messageBus, cancellationTokenSource);
105+
var testCollections = TestCases.GroupBy(tc => tc.TestCollection, TestCollectionComparer.Instance).ToArray();
106+
if (TestCollectionOrderer != null)
107+
{
108+
testCollections = TestCollectionOrderer.OrderTestCollections(testCollections).ToArray();
109+
}
107110

111+
var order = testCollections.Aggregate(String.Empty, (value, group) => value + Environment.NewLine + group.Key.DisplayName);
108112
Console.WriteLine("Queueing {0} test collections.", testCollections.Length);
113+
Console.WriteLine("Test collection will be queued in the following order: {0}", order);
109114

110115
var tasks = testCollections.Select(collectionGroup => Task.Factory.StartNew(() => RunTestCollectionAsync(messageBus, collectionGroup.Key, collectionGroup, cancellationTokenSource),
111116
cancellationTokenSource.Token,

0 commit comments

Comments
 (0)