You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

并行测试中NLog独立日志器配置及异步日志附件问题求助

并行UI测试的NLog日志问题

我查过测试并行日志相关的讨论,但问题仍未解决。我的UI测试使用如下NLog XML配置:

<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      throwExceptions="true">

    <targets>
        <target type="File" name="FileA" fileName="${basedir}/Results/FileA-${event-properties:FileId}.txt" layout="${event-properties:item=CreatedOn}  ${event-properties:item=Message}" keepFileOpen="true"/>
        <target type="File" name="FileB" fileName="${basedir}/Results/FileB-${event-properties:FileId}.txt" layout="${event-properties:item=CreatedOn}  ${event-properties:item=Message}" keepFileOpen="true"/>
    </targets>
    
    <rules>
        <logger name="FileA" minlevel="Info" writeTo="FileA" />
        <logger name="FileB" minlevel="Info" writeTo="FileB" />
    </rules>
</nlog>

其中${event-properties:FileId}对应TestContext.CurrentTest.Test.ID(每个测试的唯一标识)。

问题1

所有测试并行执行,我希望每个测试生成2个日志文件。当前100个测试是否仅共用2个日志器?能否实现每个测试拥有独立的FileA/FileB日志器?

问题2

当target设置async="true"时,其中一个日志文件未就绪,无法通过TestContext.AddTestAttachment(file)添加为测试附件;而使用LogManager.Flush()会获取其他测试的所有文件,该如何解决?

以下是Azure DevOps中添加测试附件的方法:

public static void CreateTestAttachments()
{
    LogManager.Flush();
    string filePath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "Results");

    Directory
        .EnumerateFiles(filePath, $"*{FileId}*")
        .ToList()
        .ForEach(file => TestContext.AddTestAttachment(file));
}

解答

针对问题1

当前配置下,100个测试确实共用2个日志器实例(FileA和FileB),但NLog会通过FileId事件属性自动区分日志文件路径,最终每个测试还是会生成独立的FileA-{FileId}.txt和FileB-{FileId}.txt两个文件。

如果一定要让每个测试拥有独立的日志器实例,可以通过代码动态创建:

  • 测试初始化时,基于TestContext.CurrentTest.Test.ID创建命名日志器(比如FileA-{FileId}和FileB-{FileId})
  • 动态注册对应File Target,指定专属文件名
  • 测试结束后注销这些动态创建的日志器和Target,避免内存泄漏

不过这种方式会增加复杂度,默认配置已经能满足“每个测试生成2个独立日志文件”的需求,无需强行创建独立日志器。

针对问题2

使用异步Target时,全局LogManager.Flush()会等待所有日志队列完成,导致获取到其他测试的文件。可以通过以下方式解决:

  1. 局部刷新对应日志器
    不要调用全局刷新,而是获取当前测试使用的日志器单独刷新:
var loggerA = LogManager.GetLogger("FileA");
var loggerB = LogManager.GetLogger("FileB");
// 仅刷新当前日志器的异步队列
loggerA.Flush();
loggerB.Flush();

这样只会等待当前测试发送的日志完成写入,不会影响其他测试。

  1. 验证文件就绪状态
    刷新后添加文件就绪检查,确保文件可访问再添加附件:
public static void CreateTestAttachments(string currentFileId)
{
    var loggerA = LogManager.GetLogger("FileA");
    var loggerB = LogManager.GetLogger("FileB");
    loggerA.Flush();
    loggerB.Flush();
    
    string filePath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "Results");
    var testFiles = Directory.EnumerateFiles(filePath, $"*{currentFileId}*").ToList();
    
    foreach (var file in testFiles)
    {
        // 等待文件可读写
        while (!IsFileReady(file))
        {
            Thread.Sleep(100);
        }
        TestContext.AddTestAttachment(file);
    }
}

private static bool IsFileReady(string filePath)
{
    try
    {
        using (var stream = File.Open(filePath, FileMode.Open, FileAccess.ReadWrite, FileShare.None))
        {
            return stream != null;
        }
    }
    catch (IOException)
    {
        return false;
    }
}
  1. 使用MDC绑定测试标识
    测试初始化时将FileId存入Mapped Diagnostics Context:
NLog.MappedDiagnosticsContext.Set("FileId", TestContext.CurrentTest.Test.ID);

配置中用${mdc:FileId}替代${event-properties:FileId},能更稳定地关联测试与日志文件。


内容的提问来源于stack exchange,提问作者Michał Cichoń

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 18:07:12