自定义 xUnit 单元测试顺序
前言
在理想情况下,单元测试的运行顺序不重要,最佳做法是避免对单元测试排序。但有时,你可能希望按照特定顺序运行单元测试,本文将演示如何通过自定义特性的方式对测试进行排序。
正文
首先定义一个要依赖的属性:
/// <summary>
/// 测试优先级特性
/// </summary>
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public class TestPriorityAttribute(int priority) : Attribute
{
/// <summary>
/// 优先级
/// </summary>
public int Priority { get; private set; } = priority;
}
然后实现 ITestCaseOrderer 接口:
public class PriorityOrderer : ITestCaseOrderer
{
private static readonly string assemblyName = typeof(TestPriorityAttribute).AssemblyQualifiedName!;
private static readonly string argumentName = nameof(TestPriorityAttribute.Priority);
public IEnumerable<TTestCase> OrderTestCases<TTestCase>(IEnumerable<TTestCase> testCases)
where TTestCase : ITestCase
{
var sortedMethods = new SortedDictionary<int, List<TTestCase>>();
IAttributeInfo? attributeInfo;
foreach (TTestCase testCase in testCases)
{
attributeInfo = testCase.TestMethod.Method.GetCustomAttributes(assemblyName).FirstOrDefault();
if (attributeInfo is null)
{
GetOrCreate(sortedMethods, 0).Add(testCase);
continue;
}
GetOrCreate(sortedMethods, attributeInfo.GetNamedArgument<int>(argumentName)).Add(testCase);
}
foreach (TTestCase testCase in sortedMethods.Keys.SelectMany(priority =>
sortedMethods[priority].OrderBy(internalTtestCase => internalTtestCase.TestMethod.Method.Name)))
{
yield return testCase;
}
}
private static TValue GetOrCreate<TKey, TValue>(IDictionary<TKey, TValue> dictionary, TKey key)
where TKey : struct
where TValue : new()
{
if (dictionary.TryGetValue(key, out TValue? result))
{
return result;
}
return dictionary[key] = new TValue();
}
}
最后在测试类中使用 TestPriorityAttribute 设置顺序:
[TestCaseOrderer(ordererTypeName: "Blog.Core.WebApi.Test.PriorityOrderer", ordererAssemblyName: "Blog.Core.WebApi.Test")]
public class XUnitInitDemo
{
[Fact, TestPriority(1)]
public void Test1()
{
Assert.Equal(1, 1);
}
[Fact, TestPriority(-2)]
public void Test2()
{
Assert.Equal(1, 1);
}
}
改变 Test1、Test2、测试方法的 TestPriority 特性的值,通过断点调试测试类,发现测试类的执行顺序每次都按照 Priority 从小到大的顺序执行。
注意:
测试类要添加TestCaseOrdererAttribute特性标注,特性参数的含义如下:
ordererTypeName:实现ITestCaseOrderer接口的类的完整名称。ordererAssemblyName:ordererTypeName对应类所在的程序集名称。

浙公网安备 33010602011771号