c# - 如何在 xUnit 中记录测试的执行顺序

标签 c# xunit.net

我有一个使用 xUnit.net 的大型测试集 (5k+),我在并行运行的测试中遇到并发问题。

xUnit 随机化了测试的执行顺序,这让我更难检测到问题。

我想知道是否有办法在测试执行期间记录测试开始和结束的时间。

注意:使用构造函数和处置器方法并不能解决问题,因为您无法知道构造函数/处置器上正在运行哪个测试。

注意 2:如果不是很明显,我正在寻找一种不涉及在每个测试中编写日志调用的解决方案。

谢谢,

最佳答案

好吧,我设法使用 xUnit 的 BeforeAfterTestAttribute 做到了这一点。然后我编写了下面的实用程序记录器,将结果输出到 .csv 文件。

public class LogTestExecutionAttribute: BeforeAfterTestAttribute
{
    public override void Before(MethodInfo methodUnderTest)
    {
        TestExecutionDataLogger.LogBegin(methodUnderTest);
    }

    public override void After(MethodInfo methodUnderTest)
    {
        TestExecutionDataLogger.LogEnd(methodUnderTest);
    }
}

public static class TestExecutionDataLogger
{
    private static readonly string LogFileName = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "DbCoud", $"UnitTests_{DateTime.UtcNow:yyyy_MM_dd_HH_mm}_D_{AppDomain.CurrentDomain.Id}.csv");

    private static int _startedOrder = 0;
    private static int _endedOrder = 0;
    private static readonly ConcurrentDictionary<string, testExecutionData> testDataDict = new ConcurrentDictionary<string, testExecutionData>();
    private static readonly ConcurrentQueue<string> logQueue = new ConcurrentQueue<string>();

    public static void LogBegin(MethodInfo testInfo)
    {
        var name = $"{testInfo.DeclaringType.FullName}.{testInfo.Name}";
        var order = Interlocked.Add(ref _startedOrder, 1);
        var startedUtc = DateTime.UtcNow;
        var data = testDataDict.GetOrAdd(name, new testExecutionData());
        data.StartedUtc = startedUtc;
        data.StartedOrder = order;
        data.TestName = name;
        data.Status = "Started";
        data.StartThreadId = Thread.CurrentThread.ManagedThreadId;
        writeLog(data);
    }

    public static void LogEnd(MethodInfo testInfo)
    {
        var name = $"{testInfo.DeclaringType.FullName}.{testInfo.Name}";
        var dataEndedUtc = DateTime.UtcNow;
        var order = Interlocked.Add(ref _endedOrder, 1);
        var data = testDataDict[name];
        data.EndedUtc = dataEndedUtc;
        data.EndedOrder = order;
        data.Status = "Ended";
        data.EndThreadId = Thread.CurrentThread.ManagedThreadId;
        writeLog(data);
    }

    private static void writeLog(testExecutionData data)
    {
        logQueue.Enqueue(data.ToCsvLine());

        if (data.EndedOrder == 1)
        {
            Directory.CreateDirectory(Path.GetDirectoryName(LogFileName));
            Task.Run(logWriter);
        }
    }

    private static Task logWriter()
    {
        while (true)
        {
            var logs = new List<string>();
            string result;
            while (logQueue.TryDequeue(out result))
            {
                logs.Add(result);
            }
            if (logs.Any())
            {
                File.AppendAllLines(LogFileName, logs);
            }
        }
    }

    private class testExecutionData
    {
        public int StartedOrder { get; set; }
        public int EndedOrder { get; set; }
        public DateTime StartedUtc { get; set; }
        public DateTime EndedUtc { get; set; }
        public string TestName { get; set; }
        public string Status { get; set; }
        public int StartThreadId { get; set; }
        public int EndThreadId { get; set; }

        public string ToCsvLine() { return $"{TestName};{Status};{StartedOrder};{EndedOrder};{StartedUtc:o};{EndedUtc:o};{Math.Max(0, ( EndedUtc - StartedUtc ).TotalMilliseconds)};{StartThreadId};{EndThreadId}"; }
    }
}

要使用此代码,请将 LogTestExecutionAttribute 添加到您要记录的测试类(或添加到基类;p)。

关于c# - 如何在 xUnit 中记录测试的执行顺序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40644142/

相关文章:

c# - 使用 XUnit Assert 函数比较两个 List<T>

c# - 开始在现有代码库中进行自动化集成/单元测试

visual-studio-2013 - XUnit nuget 失败(visual studio 2013)xunit.core 已经定义了依赖项

teamcity - 如何在 Teamcity 中运行针对新 .NET Core *.csproj 的 xUnit 测试?

c# - 如何为数据理论提供 List<int> ? "InlineData"

c# - HttpWebRequest AddRange 方法查询

c# - Mongo抛出 "Element name '名称'无效'异常

C# 无法转义正则表达式字符串中的引号

c# - 如何在 WinCE Compact Framework 3.5 中标记用户控件的默认事件

c# - .Net Core 控制台应用程序中的 Http 监听器?