xUnit測試的順序執行總結


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,測試

  

  

 

 

 

 

   


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM