Search code examples
c#unit-testing.net-corenlogxunit

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


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?


Solution

  • 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