97 lines
3.8 KiB
C#
97 lines
3.8 KiB
C#
/*
|
|
Usage
|
|
Add the following attribute to classes for which you want tests run in order:
|
|
[TestCaseOrderer(PriorityOrderer.Name, PriorityOrderer.Assembly)]
|
|
Then decorate your test methods with the Priority attribute.
|
|
[Fact, Priority(-10)]
|
|
public void FirstTestToRun() { }
|
|
[Fact, Priority(0)]
|
|
public void SecondTestToRun() { }
|
|
[Fact, Priority(10)]
|
|
public void ThirdTestToRunA() { }
|
|
[Fact, Priority(10)]
|
|
public void ThirdTestToRunB() { }
|
|
[Fact]
|
|
public void TestsWithNoPriorityRunLast() { }
|
|
Priorities are evaluated in numeric order (including 0 and negative numbers). If there are multiple tests with the same priority, those tests will be run in alphabetical order.
|
|
By default, tests with no explicit Priority attribute are assigned priority int.MaxValue and will be run last. You can change this by setting a DefaultPriority attribute on your test class.
|
|
[DefaultPriority(0)]
|
|
public class MyTests
|
|
{
|
|
[Fact]
|
|
public void SomeTest() { }
|
|
|
|
[Fact]
|
|
public void SomeOtherTest() { }
|
|
|
|
[Fact, Priority(10)]
|
|
public void RunMeLast() { }
|
|
}
|
|
|
|
*/
|
|
|
|
using Xunit.Abstractions;
|
|
using Xunit.Sdk;
|
|
|
|
using Tests.CoreTests.Attributes;
|
|
using System.Collections.Concurrent;
|
|
|
|
namespace CoreTests.Core
|
|
{
|
|
public class PriorityOrderer : ITestCaseOrderer
|
|
{
|
|
|
|
public const string Name = "Tests.CoreTests.PriorityOrderer";
|
|
public const string Assembly = "Tests.CoreTests";
|
|
|
|
private static string _priorityAttributeName = typeof(PriorityAttribute).AssemblyQualifiedName;
|
|
private static string _defaultPriorityAttributeName = typeof(DefaultPriorityAttribute).AssemblyQualifiedName;
|
|
private static string _priorityArgumentName = nameof(PriorityAttribute.Priority);
|
|
|
|
private static ConcurrentDictionary<string, int> _defaultPriorities = new ConcurrentDictionary<string, int>();
|
|
|
|
public IEnumerable<TTestCase> OrderTestCases<TTestCase>(IEnumerable<TTestCase> testCases) where TTestCase : ITestCase
|
|
{
|
|
var groupedTestCases = new Dictionary<int, List<ITestCase>>();
|
|
var defaultPriorities = new Dictionary<Type, int>();
|
|
|
|
foreach (var testCase in testCases)
|
|
{
|
|
var defaultPriority = DefaultPriorityForClass(testCase);
|
|
var priority = PriorityForTest(testCase, defaultPriority);
|
|
|
|
if (!groupedTestCases.ContainsKey(priority))
|
|
groupedTestCases[priority] = new List<ITestCase>();
|
|
|
|
groupedTestCases[priority].Add(testCase);
|
|
}
|
|
|
|
var orderedKeys = groupedTestCases.Keys.OrderBy(k => k);
|
|
foreach (var list in orderedKeys.Select(priority => groupedTestCases[priority]))
|
|
{
|
|
list.Sort((x, y) => StringComparer.OrdinalIgnoreCase.Compare(x.TestMethod.Method.Name, y.TestMethod.Method.Name));
|
|
foreach (TTestCase testCase in list)
|
|
yield return testCase;
|
|
}
|
|
}
|
|
|
|
private int PriorityForTest(ITestCase testCase, int defaultPriority)
|
|
{
|
|
var priorityAttribute = testCase.TestMethod.Method.GetCustomAttributes(_priorityAttributeName).SingleOrDefault();
|
|
return priorityAttribute?.GetNamedArgument<int>(_priorityArgumentName) ?? defaultPriority;
|
|
}
|
|
|
|
private int DefaultPriorityForClass(ITestCase testCase)
|
|
{
|
|
var testClass = testCase.TestMethod.TestClass.Class;
|
|
if (!_defaultPriorities.TryGetValue(testClass.Name, out var result))
|
|
{
|
|
var defaultAttribute = testClass.GetCustomAttributes(_defaultPriorityAttributeName).SingleOrDefault();
|
|
result = defaultAttribute?.GetNamedArgument<int>(_priorityArgumentName) ?? int.MaxValue;
|
|
_defaultPriorities[testClass.Name] = result;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
}
|
|
} |