cmliu
1,演示環境:windows 10企業版+Visual Studio 2019;.NET Core3.1;xUnit 2.4.1;.NET Standard 2.0.3
3,場景描述:前幾年在寫單元測試時,經常要實現從數據庫增刪改查的流水線式的單元測試代碼;每次修改業務邏輯或者代碼后,只要一次運行,就可以把核心功能邏輯調試完;這個過程中會新增數據,還要在結束時把新增的數據刪除
這中間就涉及到了順序測試的;
解決這個問題有兩種方式:1,自己寫控制執行順序的執行方法;2,使用xUnit的順序執行接口;3,自己寫jmeter腳本
剛好最近又有個東西要寫測試;於是就把.NET Core下使用xUnit順序執行的這方面的小東西做了個小總結
場景是這樣的,調用目標微服務的暴露的某個模塊的接口;需要按順序執行創建表,查詢表,修改表,刪除表接口;
本文只粘貼了核心的代碼,詳細demo代碼地址可以前往github下載:https://github.com/SaorenXi/XunitTestDemo.git
4,思路:在xUnit的xunit.core程序集中的Xunit.Sdk命名空間下;有一個用於控制執行順序的接口:ITestCaseOrderer
如下代碼為原程序集定義:
#region 程序集 xunit.core, Version=2.4.1.0, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c // C:\Users\Administrator\.nuget\packages\xunit.extensibility.core\2.4.1\lib\netstandard1.1\xunit.core.dll #endregion using System.Collections.Generic; using Xunit.Abstractions; namespace Xunit.Sdk { // // 摘要: // A class implements this interface to participate in ordering tests for the test // runner. Test case orderers are applied using the Xunit.TestCaseOrdererAttribute, // which can be applied at the assembly, test collection, and test class level. public interface ITestCaseOrderer { // // 摘要: // Orders test cases for execution. // // 參數: // testCases: // The test cases to be ordered. // // 返回結果: // The test cases in the order to be run. IEnumerable<TTestCase> OrderTestCases<TTestCase>(IEnumerable<TTestCase> testCases) where TTestCase : ITestCase; } }
5,為了做方法順序控制;定義一個名為OrderAttribute屬性標簽,標簽上有個名為Sort的int型屬性,用於標記方法的順序;如下定義(示例是定義在:XUnitTest.Orders命名空間下)
using System; namespace XUnitTest.Orders { /// <summary> /// 測試方法的執行順序 /// </summary> [AttributeUsage(AttributeTargets.Method)] public class OrderAttribute : Attribute { /// <summary> /// 順序 /// </summary> public int Sort { get; set; } public OrderAttribute(int sort) { this.Sort = sort; } } }
6,實現ITestCaseOrderer接口(//按照Order標簽上的Sort屬性,從小到大的順序執行),如下定義(示例定義在:SchemaTest命名空間下)
using System.Collections.Generic; using System.Linq; using Xunit.Abstractions; using Xunit.Sdk; using XUnitTest.Orders; namespace SchemaTest { /// <summary> /// 單元測試的排序策略 /// </summary> public class TestOrders : ITestCaseOrderer { /// <summary> /// 執行順序 /// </summary> /// <typeparam name="TTestCase"></typeparam> /// <param name="testCases"></param> /// <returns></returns> public IEnumerable<TTestCase> OrderTestCases<TTestCase>(IEnumerable<TTestCase> testCases) where TTestCase : ITestCase { string 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"); //按照Order標簽上的Sort屬性,從小到大的順序執行 return sortX - sortY; }); return result; } } }
7,使用;在目標的單元測試類上打上標簽使用順序執行實現類的標簽;如下定義(示例中的目標類為:SchemaTest命名空間下的SchemaApiTest類)
//省略其他代碼 using Xunit; using XUnitTest.Orders; namespace SchemaTest { //[TestCaseOrderer("ITestCaseOrderer的實現類名稱", "ITestCaseOrderer的實現類所在的程序集名稱")] [TestCaseOrderer("SchemaTest.TestOrders", "SchemaTest")] public class SchemaApiTest { //省略其他代碼 } }
8,在目標的測試方法上打上Order標簽,定義執行順序,如下定義(示例使用的是mock數據和接口)
using Xunit; using XUnitTest.Orders; namespace SchemaTest { [TestCaseOrderer("SchemaTest.TestOrders", "SchemaTest")] public class SchemaApiTest { private string _testSchemaCode = $"xunittest123"; private static SchemaDTO _schemaDto = null; /// <summary> /// 創建記錄 /// </summary> [Fact, Order(1)] public void AddSchema() { var response = new MockClient().AddSchema(new SchemaDTO { SchemaCode = _testSchemaCode, Name = "哈哈" }); Assert.True(response); } /// <summary> /// 查詢剛剛創建的記錄 /// </summary> [Fact, Order(2)] public void GetSchema() { var response = new MockClient().GetSchema(_testSchemaCode); //臨時記錄 _schemaDto = response; Assert.NotNull(response); Assert.Equal(_testSchemaCode, response.SchemaCode); Assert.Equal("哈哈", response.Name); } /// <summary> /// 更新剛剛創建的數據記錄 /// </summary> [Fact, Order(3)] public void UpdateSchema() { _schemaDto.Name = "jiujiu"; var response = new MockClient().UpdateSchema(_schemaDto); Assert.True(response); } /// <summary> /// 查詢更新后的記錄 /// </summary> [Fact, Order(4)] public void GetAfterUpdatedSchema() { var response = new MockClient().GetSchema(_testSchemaCode); Assert.NotNull(response); Assert.Equal(_testSchemaCode, response.SchemaCode); Assert.Equal("jiujiu", response.Name); } /// <summary> /// 刪除記錄 /// </summary> [Fact, Order(5)] public void RemoveSchema() { var response = new MockClient().RemoveSchema(_testSchemaCode); Assert.True(response); } } }
9,測試