按给定顺序执行测试

通常,你的测试应该以执行顺序无关紧要的方式创建。然而,如果你需要打破这个规则,总会有一个边缘情况。

我遇到的一个场景是使用 R.NET,在给定的过程中,你只能初始化一个 R 引擎,一旦处理完就无法重新初始化。我的一个测试恰好处理了处理引擎的问题,如果这个测试在任何其他测试之前运行,它们就会失败。

你将在下面找到我使用 Nunit 按顺序运行的代码片段。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using NUnit.Framework;
using RSamples;
 
public class OrderedTestAttribute : Attribute
{
    public int Order { get; set; }

    public OrderedTestAttribute(int order)
    {
        this.Order = order;
    }
}

public class TestStructure
{
    public Action Test;
}

public class SampleTests
{
    [TearDown]
    public void CleanUpAfterTest()
    {
        REngineExecutionContext.ClearLog();
    }

    [OrderedTest(0)]
    public void Test1(){}

    [OrderedTest(1)]
    public void Test2(){}

    [OrderedTest(2)]
    public void Test3(){}

    [TestCaseSource(sourceName: "TestSource")]
    public void MainTest(TestStructure test)
    {
        test.Test();
    }

    public static IEnumerable<TestCaseData> TestSource
    {
        get
        {
            var assembly = Assembly.GetExecutingAssembly();
            Dictionary<int, List<MethodInfo>> methods = assembly
                .GetTypes()
                .SelectMany(x => x.GetMethods())
                .Where(y => y.GetCustomAttributes().OfType<OrderedTestAttribute>().Any())
                .GroupBy(z => z.GetCustomAttribute<OrderedTestAttribute>().Order)
                .ToDictionary(gdc => gdc.Key, gdc => gdc.ToList());

            foreach (var order in methods.Keys.OrderBy(x => x))
            {
                foreach (var methodInfo in methods[order])
                {
                    MethodInfo info = methodInfo;
                    yield return new TestCaseData(
                        new TestStructure
                        {
                            Test = () =>
                            {
                                object classInstance = Activator.CreateInstance(info.DeclaringType, null);
                                info.Invoke(classInstance, null);
                            }
                        }).SetName(methodInfo.Name);
                }
            }
        }
    }
}