简体   繁体   English

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

[英]How can I log the execution order of tests in xUnit

I have a large test set (5k+) using xUnit.net, and I'm having concurrency problems among tests running in parallel. 我有一个使用xUnit.net的大型测试集(5k +),并且我在并行运行的测试中遇到并发问题。

xUnit randomizes the execution order of tests, which makes it harder for me to detect the issue. xUnit使测试的执行顺序随机化,这使我更难以检测到问题。

I'd like to know whether is there a way to log, during test execution, the moment a test starts and the moment it ends. 我想知道是否有一种方法可以在测试执行期间记录测试开始的时刻和结束的时刻。

Note: Using constructor and disposer methods does not cut it, because you cannot know which test is being run on the constructor/disposer. 注意:使用构造函数和disposer方法不会削减它,因为您无法知道构造函数/ disposer上正在运行哪个测试。

Note 2: In case it is not obvious, I'm looking for a solution that doesn't involve writing log call in each test. 注2:如果不明显,我正在寻找一种不涉及在每次测试中编写日志调用的解决方案。

Thanks, 谢谢,

Well, I managed to do it using the BeforeAfterTestAttribute from xUnit. 好吧,我设法使用xUnit中的BeforeAfterTestAttribute来完成它。 Then I wrote the utility logger below to output the results to a .csv file. 然后我编写了下面的实用程序记录器,将结果输出到.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}"; }
    }
}

To use this code, add the LogTestExecutionAttribute to the test classes you want to log (or to the base classes ;p). 要使用此代码,请将LogTestExecutionAttribute添加到要记录的测试类(或基类; p)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何验证XUnit Moq中的执行顺序? - How to verify order of execution in XUnit Moq? 如何将值传递给接受可为空的小数的 xUnit 测试? - How can I pass values to xUnit tests that accept a nullable decimal? 如何在执行时输出XUnit测试涉及的每一行? - How can I output every line an XUnit test touches upon execution? 在某个进程完成后,如何从控制台自动触发 Xunit 测试? - How can I trigger Xunit tests from console automatically aftter e certain process has finished? 如何在 XUNIT 中运行所有测试之前和之后运行方法,同时保持固定夹具? - How can I run a a method prior and after all tests are run in XUNIT, while Keeping a fixed Fixture? xUnit 是否支持“相同的测试,不同的设置”? 或者我如何编写在本地为开发人员运行的测试,并在管道中测试部署? - Does xUnit support "same tests, different setups"? Or how can I write tests that run locally for dev, and in a pipeline to test deployment? Azure xunit 测试的管道并发(非并行)测试执行 - Azure pipeline concurrent (not parallel) tests execution for xunit tests 如何在xunit测试中调试理论 - How to debug theories in xunit tests 如何禁用XUnit.Net中标有自定义事实的所有测试的测试并行执行 - How to disable test parallel execution for all tests marked with custom Facts in XUnit.Net 如何订购属于一个测试集合但分布在多个测试类中的 xUnit 测试? - How to order xUnit tests belonging to one test collection but spread across multiple test classes?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM