如何在 .NET Core 的 xUnit 测试中使用 NLog?

How to use NLog in xUnit tests from .NET Core?

我正在尝试通过 NLog 日志库从基于 .NET Core 3.1 的 xUnit 测试用例中输出一些日志消息。通过 NLog 进行日志记录在我的主应用程序中工作正常,但测试用例不会输出任何消息。

认为我正在做这个相关问题中建议的一切:

但是,不知何故,我无法弄清楚缺少什么。我已将我的代码缩减为一个看起来非常简单的最小示例,但仍然不输出任何内容:

using NLog;
using NLog.Config;
using NLog.Targets;
using System;
using Xunit;
using Xunit.Abstractions;

namespace UnitTests
{
    public class LoggingTest
    {
        public LoggingTest(ITestOutputHelper output)
        {
            this.output = output;
        }

        private readonly ITestOutputHelper output;

        [Fact]
        public void TestLog()
        {
            var target = new MemoryTarget {Layout = "${message}"};

            LogManager.Configuration ??= new LoggingConfiguration();
            LogManager.Configuration.AddRuleForAllLevels(target);

            LogManager.GetCurrentClassLogger().Info("Hello, World!");

            output.WriteLine("{0} line(s) logged:\n{1}", target.Logs.Count, String.Join("\n", target.Logs));
        }
    }
}

预期输出:

1 line(s) logged:
Hello, World!

实际输出:

0 line(s) logged:


作为进一步的跟踪,我在各个地方读到,如果 appsettings.json 文件的 Logging 部分中存在某些设置,NLog 只会在 .NET Core 3.1 项目中写入内容。我认为这部分也必须添加到我们的主应用程序的 appsettings.json 文件中。

不过,我不确定如何将这些知识转移到单元测试中,因为它们似乎没有随 appsettings.json 文件一起提供。我尝试将主 appsettings.json 文件复制到单元测试的输出目录(我认为,当 运行 来自 ReSharper 时,它们的执行目录),但无济于事。


我错过了什么?

要应用配置,您需要分配 LogManager.Configuration,喜欢

LogManager.Configuration = config;

工作示例:

[Fact]
public void TestLog()
{
    var target = new MemoryTarget { Layout = "${message}" };

    var config = new LoggingConfiguration();

    config.AddRuleForAllLevels(target);
    LogManager.Configuration = config; // <-- assign here
    LogManager.GetCurrentClassLogger().Info("Hello, World!");

    output.WriteLine("{0} line(s) logged:\n{1}", target.Logs.Count, String.Join("\n", target.Logs));

    Assert.Equal(1, target.Logs.Count);
}

奖励:并行测试

奖金,如果你喜欢并行测试(谁不喜欢 ;)) - 创建一个新的 LogFactory 而不是分配全局 LogManager.

像这样:


[Fact]
public void TestLogParallelSafe()
{
    var logFactory = new LogFactory();

    var target = new MemoryTarget { Layout = "${message}" };

    var config = new LoggingConfiguration();

    config.AddRuleForAllLevels(target);
    logFactory.Configuration = config;
    logFactory.GetCurrentClassLogger().Info("Hello, World!");

    output.WriteLine("{0} line(s) logged:\n{1}", target.Logs.Count, String.Join("\n", target.Logs));

    Assert.Equal(1, target.Logs.Count);
}

当然,如果其他代码正在使用 LogManager,您将无法断言这些日志。

.NET 核心集成

As one further trace, I have read in various places that NLog will only write something in .NET Core 3.1 projects if certain settings are present in a Logging section of the appsettings.json file. I think this section also had to be added to our main application's appsettings.json file.

这仅在与 ASP.NET 核心集成时才需要 - 例如注入 Microsoft 的 ILogger<T> 时。这里不需要。如需进一步参考,请参阅 Getting started with ASP.NET Core 3 · NLog/NLog Wiki