有的時候我們會對程式進行單元測試, 為了測試的效果以及後期的維護, 我一般會將各個測試拆開, 根據需要測試的類分到各個型別中, 不過在實際操作的時候就出現了一些意想不到的問題, 各個測試的執行是亂序的, 按照我自己寫測試的習慣, 假如我需要測試新寫的增刪改查的功能, 我會將增刪改查分開測試, 會按照 新增-->查詢-->修改-->刪除 這樣的順序編寫, 在我的預想中新增操作應當是最先執行的, 但是在實際的執行過程中完全不是這樣, 隨機的順序對這樣的測試會有巨大的影響
所以就需要控制測試的執行順序
為測試用例排序
一般而言, 我們會將增刪改查全都放在一個測試集中
public class UserInfoTest
{
[Fact]
public void AddTest()
{
}
[Fact]
public void ReadTest()
{
}
[Fact]
public void UpdateTest()
{
}
[Fact]
public void DeleteTest()
{
}
}
上面就是增刪查改的測試用例, 儘管在寫的時候看起來是按照我所希望的那樣進行排序的, 但是在實際的執行過程卻有可能是完全亂序的, 而我需要他們按照上面的順序執行
實現ITestCaseOrderer
Xunit 中有一個 TestCaseOrdererAttribute
, 加在測試類上時可以對測試類中包含的測試用例進行排序
但若是需要讓 TestCaseOrdererAttribute
起效, 我們還需要實現一個介面 ITestCaseOrderer
public class TestOrders : ITestCaseOrderer
{
public IEnumerable<TTestCase> OrderTestCases<TTestCase>(IEnumerable<TTestCase> testCases) where TTestCase : ITestCase
{
var result = testCases.ToList();
return result;
}
}
透過實現 ITestCaseOrderer
我們可以獲取到測試用例, 之後只需要將測試用例重新進行排序, 排序成預期中需要的順序即可
最簡單的就是根據名字來進行排序, 此時只需要使用 result.OrderBy(item => item.DisplayName)
就差不多可以了
但是為了嚴謹以及後續的可維護性, 最好在做一個新的 Attribute
對需要排序的測試用例進行標記
新建OrderAttribute
[AttributeUsage(AttributeTargets.Method)]
public class OrderAttribute : Attribute
{
public int Sort { get; set; }
public OrderAttribute(int sort)
{
this.Sort = sort;
}
}
OrderAttribute
的構成非常簡單, 其中只包含一個 Sort
用來進行排序
完善TestOrders的實現
public class TestOrders : ITestCaseOrderer
{
public IEnumerable<TTestCase> OrderTestCases<TTestCase>(IEnumerable<TTestCase> testCases) where TTestCase : ITestCase
{
var typeName = typeof(OrderAttribute).AssemblyQualifiedName;
var result = testCases.ToList();
result.Sort((x, y) =>
{
var xOrder = x.TestMethod.Method.GetCustomAttributes(typeName)?.FirstOrDefault();
if (xOrder == null)
{
return 0;
}
var yOrder = y.TestMethod.Method.GetCustomAttributes(typeName)?.FirstOrDefault();
if (yOrder == null)
{
return 0;
}
var sortX = xOrder.GetNamedArgument<int>("Sort");
var sortY = yOrder.GetNamedArgument<int>("Sort");
return sortX - sortY;
});
return result;
}
}
完善 TestOrders
的實現, 使得測試用例可以按照順序進行排序
測試用例打標
[TestCaseOrderer("TestOrders這個型別所在的namespace.TestOrders", "TestOrders這個型別所在的namespace")]
public class UserInfoTest
{
[Fact, Order(0)]
public void AddTest()
{
}
[Fact, Order(1)]
public void ReadTest()
{
}
[Fact, Order(2)]
public void UpdateTest()
{
}
[Fact, Order(3)]
public void DeleteTest()
{
}
}
TestCaseOrdererAttribute
接收兩個引數, 一個是可以用來確定之前實現的 TestOrders
的完整名稱空間, 第二個是 TestOrders
所在的名稱空間
這兩個引數主要的功能就是確定 TestOrders
的位置, Xunit會根據這兩個引數找到 TestOrders
並且呼叫排序的方法
然後在需要進行排序的測試用例上使用 [Order]
打標, 傳入自定義的排序, 然後在我們使用 dotnet test
就會按照傳入的排序執行測試用例了