Skip to content

Commit c95d7bc

Browse files
committed
Add DefaultPriorityAttribute
1 parent ab9e046 commit c95d7bc

10 files changed

+248
-22
lines changed

README.md

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,22 @@ public void ThirdTestToRunB() { }
3535
public void TestsWithNoPriorityRunLast() { }
3636
```
3737

38-
### Notes
38+
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.
3939

40-
- Priorities are evaluated in numeric order (including 0 and negative numbers)
41-
- Multiple tests with the same priority will be run in alphabetical order
42-
- Tests with no explicit `Priority` attribute are assigned priority `int.MaxValue` and will be run last
40+
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.
41+
42+
```csharp
43+
[DefaultPriority(0)]
44+
public class MyTests
45+
{
46+
[Fact]
47+
public void SomeTest() { }
48+
49+
[Fact]
50+
public void SomeOtherTest() { }
51+
52+
[Fact, Priority(10)]
53+
public void RunMeLast() { }
54+
}
55+
```
4356

Xunit.Priority.Tests/PriorityOrdererTests.cs renamed to Xunit.Priority.Tests/BasicPriorityTests.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,12 @@
99

1010
namespace Xunit.Priority.Tests
1111
{
12-
public class PriorityOrdererTests: TestsBase
12+
public class BasicPriorityTests: TestsBase
1313
{
14+
#pragma warning disable 169
1415
private static bool[] _counter;
15-
16+
#pragma warning restore 169
17+
1618

1719
[Fact, Priority(10)]
1820
public void Test3A() => VerifyAndFlip(2);
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
using System.Threading.Tasks;
6+
using Xunit;
7+
using Xunit.Priority;
8+
using FluentAssertions;
9+
10+
namespace Xunit.Priority.Tests
11+
{
12+
public class NoPriorityTests: TestsBase
13+
{
14+
#pragma warning disable 169
15+
private static bool[] _counter;
16+
#pragma warning restore 169
17+
18+
19+
[Fact]
20+
public void Test3A() => VerifyAndFlip(2);
21+
22+
[Fact]
23+
public void Test1() => VerifyAndFlip(0);
24+
25+
[Fact]
26+
public void Test5() => VerifyAndFlip(5);
27+
28+
[Fact]
29+
public void Test2() => VerifyAndFlip(1);
30+
31+
[Fact]
32+
public void Test4() => VerifyAndFlip(4);
33+
34+
[Fact]
35+
public void Test3B() => VerifyAndFlip(3);
36+
}
37+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
using System.Threading.Tasks;
6+
using Xunit;
7+
using Xunit.Priority;
8+
using FluentAssertions;
9+
10+
namespace Xunit.Priority.Tests
11+
{
12+
[DefaultPriority(int.MinValue)]
13+
public class OnePriorityMinDefaultTests: TestsBase
14+
{
15+
#pragma warning disable 169
16+
private static bool[] _counter;
17+
#pragma warning restore 169
18+
19+
20+
[Fact]
21+
public void Test3A() => VerifyAndFlip(2);
22+
23+
[Fact]
24+
public void Test1() => VerifyAndFlip(0);
25+
26+
[Fact]
27+
public void Test5() => VerifyAndFlip(4);
28+
29+
[Fact]
30+
public void Test2() => VerifyAndFlip(1);
31+
32+
[Fact]
33+
public void Test4() => VerifyAndFlip(3);
34+
35+
[Fact, Priority(10)]
36+
public void Test3B() => VerifyAndFlip(5);
37+
}
38+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
using System.Threading.Tasks;
6+
using Xunit;
7+
using Xunit.Priority;
8+
using FluentAssertions;
9+
10+
namespace Xunit.Priority.Tests
11+
{
12+
[DefaultPriority(int.MaxValue)]
13+
public class PriorityWithMaxDefaultTests: TestsBase
14+
{
15+
#pragma warning disable 169
16+
private static bool[] _counter;
17+
#pragma warning restore 169
18+
19+
20+
[Fact, Priority(10)]
21+
public void Test3A() => VerifyAndFlip(2);
22+
23+
[Fact, Priority(-10)]
24+
public void Test1() => VerifyAndFlip(0);
25+
26+
[Fact]
27+
public void Test5() => VerifyAndFlip(5);
28+
29+
[Fact, Priority(0)]
30+
public void Test2() => VerifyAndFlip(1);
31+
32+
[Fact, Priority(20)]
33+
public void Test4() => VerifyAndFlip(4);
34+
35+
[Fact, Priority(10)]
36+
public void Test3B() => VerifyAndFlip(3);
37+
}
38+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
using System.Threading.Tasks;
6+
using Xunit;
7+
using Xunit.Priority;
8+
using FluentAssertions;
9+
10+
namespace Xunit.Priority.Tests
11+
{
12+
[DefaultPriority(0)]
13+
public class PriorityWithZeroDefault: TestsBase
14+
{
15+
#pragma warning disable 169
16+
private static bool[] _counter;
17+
#pragma warning restore 169
18+
19+
20+
[Fact, Priority(50)]
21+
public void Test3A() => VerifyAndFlip(5);
22+
23+
[Fact, Priority(-10)]
24+
public void Test1() => VerifyAndFlip(1);
25+
26+
[Fact]
27+
public void Test5() => VerifyAndFlip(3);
28+
29+
[Fact, Priority(0)]
30+
public void Test2() => VerifyAndFlip(2);
31+
32+
[Fact, Priority(-40)]
33+
public void Test4() => VerifyAndFlip(0);
34+
35+
[Fact, Priority(10)]
36+
public void Test3B() => VerifyAndFlip(4);
37+
}
38+
}

Xunit.Priority.Tests/Xunit.Priority.Tests.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@
88

99
<ItemGroup>
1010
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.9.0" />
11-
<PackageReference Include="xunit" Version="2.4.0" />
12-
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.0" />
11+
<PackageReference Include="xunit" Version="2.3.1" />
12+
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />
1313
<PackageReference Include="FluentAssertions" Version="5.8.0" />
1414
</ItemGroup>
1515

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/**
2+
* Copyright 2018-2019 Aaron Sherber
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
using System;
18+
using System.Collections.Generic;
19+
using System.Linq;
20+
using System.Text;
21+
using System.Threading.Tasks;
22+
23+
namespace Xunit.Priority
24+
{
25+
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
26+
public class DefaultPriorityAttribute: Attribute
27+
{
28+
public DefaultPriorityAttribute(int priority)
29+
{
30+
Priority = priority;
31+
}
32+
33+
public int Priority { get; private set; }
34+
}
35+
}

Xunit.Priority/PriorityOrderer.cs

Lines changed: 36 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/**
2-
* Copyright 2018 Aaron Sherber
2+
* Copyright 2018-2019 Aaron Sherber
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -15,6 +15,7 @@
1515
*/
1616

1717
using System;
18+
using System.Collections.Concurrent;
1819
using System.Collections.Generic;
1920
using System.Linq;
2021
using System.Text;
@@ -29,31 +30,54 @@ public class PriorityOrderer : ITestCaseOrderer
2930
public const string Name = "Xunit.Priority.PriorityOrderer";
3031
public const string Assembly = "Xunit.Priority";
3132

32-
private static string _priorityAttribute = typeof(PriorityAttribute).AssemblyQualifiedName;
33-
private static string _priority = nameof(PriorityAttribute.Priority);
33+
private static string _priorityAttributeName = typeof(PriorityAttribute).AssemblyQualifiedName;
34+
private static string _defaultPriorityAttributeName = typeof(DefaultPriorityAttribute).AssemblyQualifiedName;
35+
private static string _priorityArgumentName = nameof(PriorityAttribute.Priority);
36+
37+
private static ConcurrentDictionary<string, int> _defaultPriorities = new ConcurrentDictionary<string, int>();
3438

3539
public IEnumerable<TTestCase> OrderTestCases<TTestCase>(IEnumerable<TTestCase> testCases) where TTestCase : ITestCase
3640
{
37-
var dict = new Dictionary<int, List<TTestCase>>();
41+
var groupedTestCases = new Dictionary<int, List<ITestCase>>();
42+
var defaultPriorities = new Dictionary<Type, int>();
3843

39-
foreach (TTestCase testCase in testCases)
44+
foreach (var testCase in testCases)
4045
{
41-
var attr = testCase.TestMethod.Method.GetCustomAttributes(_priorityAttribute).SingleOrDefault();
42-
int priority = attr?.GetNamedArgument<int>(_priority) ?? int.MaxValue;
46+
var defaultPriority = DefaultPriorityForClass(testCase);
47+
var priority = PriorityForTest(testCase, defaultPriority);
4348

44-
if (!dict.ContainsKey(priority))
45-
dict[priority] = new List<TTestCase>();
49+
if (!groupedTestCases.ContainsKey(priority))
50+
groupedTestCases[priority] = new List<ITestCase>();
4651

47-
dict[priority].Add(testCase);
52+
groupedTestCases[priority].Add(testCase);
4853
}
4954

50-
var orderedKeys = dict.Keys.OrderBy(k => k);
51-
foreach (var list in orderedKeys.Select(priority => dict[priority]))
55+
var orderedKeys = groupedTestCases.Keys.OrderBy(k => k);
56+
foreach (var list in orderedKeys.Select(priority => groupedTestCases[priority]))
5257
{
5358
list.Sort((x, y) => StringComparer.OrdinalIgnoreCase.Compare(x.TestMethod.Method.Name, y.TestMethod.Method.Name));
5459
foreach (TTestCase testCase in list)
5560
yield return testCase;
5661
}
5762
}
63+
64+
private int PriorityForTest(ITestCase testCase, int defaultPriority)
65+
{
66+
var priorityAttribute = testCase.TestMethod.Method.GetCustomAttributes(_priorityAttributeName).SingleOrDefault();
67+
return priorityAttribute?.GetNamedArgument<int>(_priorityArgumentName) ?? defaultPriority;
68+
}
69+
70+
private int DefaultPriorityForClass(ITestCase testCase)
71+
{
72+
var testClass = testCase.TestMethod.TestClass.Class;
73+
if (!_defaultPriorities.TryGetValue(testClass.Name, out var result))
74+
{
75+
var defaultAttribute = testClass.GetCustomAttributes(_defaultPriorityAttributeName).SingleOrDefault();
76+
result = defaultAttribute?.GetNamedArgument<int>(_priorityArgumentName) ?? int.MaxValue;
77+
_defaultPriorities[testClass.Name] = result;
78+
}
79+
80+
return result;
81+
}
5882
}
5983
}

Xunit.Priority/Xunit.Priority.csproj

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
1-
<Project Sdk="Microsoft.NET.Sdk">
1+
<Project Sdk="Microsoft.NET.Sdk">
22

33
<PropertyGroup>
44
<TargetFrameworks>netstandard1.1;net452</TargetFrameworks>
55
<AssemblyName>Xunit.Priority</AssemblyName>
66
<RootNamespace>Xunit.Priority</RootNamespace>
77
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
88
<Authors>Aaron Sherber</Authors>
9-
<Copyright>2018</Copyright>
9+
<Copyright>2018-2019</Copyright>
1010
<PackageTags>xunit priority order</PackageTags>
1111
<Company />
1212
<Description>Provides an ITestCaseOrderer that allows you to control the order of execution of Xunit tests within a class.</Description>
13+
<PackageReleaseNotes>Added DefaultPrority attribute</PackageReleaseNotes>
1314
<PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>
1415
<RepositoryUrl>https://github.com/asherber/Xunit.Priority</RepositoryUrl>
1516
<RepositoryType>git</RepositoryType>

0 commit comments

Comments
 (0)