How to configure xUnit test to work with NLog?

Viewed 398

To enable output in test class, as mentioned in the following answer xUnit.net does not capture console output you need to provide the following setup:

public class OutputTest
{
    private readonly ITestOutputHelper _testOutputHelper;

    public OutputTest(ITestOutputHelper testOutputHelper)
    {
        _testOutputHelper = testOutputHelper;
    }

    [Fact]
    public void MyFact()
    {
        _testOutputHelper.WriteLine("Hello world!");
        //this should result in writing to _testOutputHelper too
        LogManager.GetCurrentClassLogger().Info("Hello world!");
    }
}

How do I connect _testOutputHelper with NLog? Is it possible to write to ITestOutputHelper when there is done some logging by NLog (in application or in referenced library)?

2 Answers

You can create a custom NLog target that writes to Xunit's ITestOutputHelper:

using NLog;
using NLog.Targets;
using Xunit.Abstractions;

namespace YourNamespace
{
    /// <summary>
    /// Writes log messages to Xunit's ITestOutputHelper.
    /// </summary>
    public class XunitLoggerTarget : TargetWithLayout
    {
        private readonly ITestOutputHelper helper;

        public XunitLoggerTarget(ITestOutputHelper helper)
        {
            this.helper = helper;
        }

        protected override void Write(LogEventInfo logEvent)
        {
            var logMessage = Layout.Render(logEvent);
            helper.WriteLine(logMessage);
        }
    }
}

Then, in your Xunit test classes, add a constructor argument for ITestOutputHelper, and configure NLog to use the XunitLoggerTarget:

using NLog;
using NLog.Config;
using Xunit.Abstractions;

namespace YourNamespace
{
    public class NLoggedTest
    {
        public NLoggedTest(ITestOutputHelper testOutputHelper)
        {
            var config = new LoggingConfiguration();
            var target = new XunitLoggerTarget(testOutputHelper);
            config.AddTarget("Xunit", target);

            config.LoggingRules.Add(new LoggingRule("*", LogLevel.Trace, target));
            LogManager.Configuration = config;
        }

        // your tests/facts/theories here
    }
}

You could make NLoggedTest an abstract/base class and write your other test classes to inherit from it.

You can use the NLog MethodCallTarget for calling the testOutputHelper:

public class NLoggedTest
{
    public NLoggedTest(ITestOutputHelper testOutputHelper)
    {
        var target = new NLog.Targets.MethodCallTarget("Xunit", (evt,args) => testOutputHelper.WriteLine(evt.FormattedMessage + evt.Exception?.ToString()));
        var config = new LoggingConfiguration();
        config.LoggingRules.Add(new LoggingRule("*", LogLevel.Trace, target));
        LogManager.Configuration = config;
    }

    // your tests/facts/theories here
}

See also: https://github.com/NLog/NLog/wiki/MethodCall-target

Related