且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

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

更新时间:2023-02-16 16:12:59

要应用配置,您需要assign LogManager.Configuration,如

LogManager.Configuration = config;

工作示例:

[事实]公共无效测试日志(){var target = new MemoryTarget { Layout = "${message}";};var config = new LoggingConfiguration();config.AddRuleForAllLevels(目标);LogManager.Configuration = config;//<-- 在这里赋值LogManager.GetCurrentClassLogger().Info("Hello, World!");output.WriteLine({0} 行记录:\n{1}", target.Logs.Count, String.Join(\n", target.Logs));Assert.Equal(1, target.Logs.Count);}

奖励:并行测试

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

像这样:

[事实]public void TestLogParallelSafe(){var logFactory = new LogFactory();var target = new MemoryTarget { Layout = "${message}";};var config = new LoggingConfiguration();config.AddRuleForAllLevels(目标);logFactory.Configuration = config;logFactory.GetCurrentClassLogger().Info(Hello, World!");output.WriteLine({0} 行已记录:\n{1}", target.Logs.Count, String.Join(\n", target.Logs));Assert.Equal(1, target.Logs.Count);}

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

.NET Core 集成

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

这仅在与 ASP.NET Core 集成时才需要 - 例如当注入来自 Microsoft 的 ILogger 时.这里不需要.如需进一步参考,请参阅 ASP 入门.NET Core 3 · NLog/NLog 维基

I am trying to output some log messages from within .NET Core 3.1-based xUnit test cases by means of the NLog logging library. Logging by means of NLog works fine in my main application, but the test cases just won't output any messages.

I think I am doing everything suggested in this related question: NLog works in ASP.NET Core App but not in .NET Core xUnit Test Project

Somehow, though, I cannot figure out what is missing. I have reduced my code into a minimal sample that seems very straightforward, but still does not output anything:

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));
        }
    }
}

Expected output:

1 line(s) logged:
Hello, World!

Actual output:

0 line(s) logged:


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.

I am not sure how to transfer this knowledge to the unit tests, though, as they do not appear to come with an appsettings.json file. I have tried copying the main appsettings.json file to the output directory of the unit tests (which is, I think, their execution directory when run from within ReSharper), but to no avail.


What am I missing?

To apply the config, you need to assign LogManager.Configuration, like

LogManager.Configuration = config;

Working example:

[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);
}

Bonus: tests in parallel

Bonus, if you like tests in parallel (who doesn't ;)) - create a new LogFactory instead of assigning the global LogManager.

Like this:


[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);
}

Of course if other code is using the LogManager, you can't assert those logs.

.NET Core integration

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.

This is only needed when integrating with ASP.NET Core - e.g. when injection the ILogger<T> from Microsoft. That's is not needed here. For further reference, see Getting started with ASP.NET Core 3 · NLog/NLog Wiki