从下面的示例代码可以运行以重现问题,我们有2个自定义LayoutRenderer
:RendererOne
和RendererTwo
。然后分别在测试TestA
和TestB
中使用这两个。当我一次运行一个测试时,我没有遇到任何问题。但是,如果要通过XUnit的“全部运行”按钮在一个示例中运行它们,我会得到失败的断言,如下图所示:
当""
的Append方法遇到LogEventInfo
对象时,附加到目标的渲染器似乎在输出中产生空字符串(LayoutRenderer
)。正如在示例代码中可以看到的那样,我启用了InternalLogger
但是,它没有告诉我可能出错的地方。我认为我已经在如何使用自定义渲染器方面做了一切正确的事情:
TestA
和TestB
的构造函数)TestTarget
(参考:Log
的构造函数)我不知道为什么没有正确处理日志事件的布局没有注册。这是另一个屏幕截图,说明了这种情况:
请注意,上面的屏幕截图没有关联,但用于说明情况。任何解释/修复/如何解决问题都是最受欢迎的。
using FluentAssertions;
using NLog;
using NLog.Common;
using NLog.Config;
using NLog.LayoutRenderers;
using NLog.Layouts;
using NLog.Targets;
using System;
using System.Collections.Concurrent;
using System.IO;
using System.Text;
using Xunit;
namespace LoggingTests
{
[Target("test-target")]
class TestTarget : TargetWithLayout
{
public ConcurrentBag<string> Messages = new ConcurrentBag<string>();
public TestTarget(string name)
{
Name = name;
}
protected override void Write(LogEventInfo logEvent)
{
Messages.Add(Layout.Render(logEvent));
}
}
class Log
{
private string _target_name;
public Log(Layout layout,
string target_name)
{
if (LogManager.Configuration == null)
{
LogManager.Configuration = new LoggingConfiguration();
InternalLogger.LogFile = Path.Combine(Environment.CurrentDirectory,
"nlog.debug.txt");
InternalLogger.LogLevel = LogLevel.Trace;
}
_target_name = target_name;
if (LogManager.Configuration.FindTargetByName<TestTarget>(_target_name) == null)
{
// Create the target:
TestTarget target = new TestTarget(_target_name);
// Register the target:
Target.Register<TestTarget>(_target_name);
// Assign layout to target:
target.Layout = layout;
// Add the target to the configuration:
LogManager.Configuration.AddTarget(_target_name,
target);
// Add a logging rule pertaining to the above target:
LogManager.Configuration.AddRule(LogLevel.Trace,
LogLevel.Fatal,
target);
// Because configuration has been modified programatically, we have to reconfigure all loggers:
LogManager.ReconfigExistingLoggers();
}
}
public void AssertLogContains(string message)
{
TestTarget target = LogManager.Configuration
.FindTargetByName<TestTarget>(_target_name);
target.Messages.Should().Contain(message);
}
}
class Loggable
{
private Logger _logger;
public Loggable()
{
_logger = LogManager.GetCurrentClassLogger();
}
public void Error(string message)
{
_logger.Error(message);
}
public void Info(string message)
{
_logger.Info(message);
}
}
[LayoutRenderer("renderer-one")]
class RendererOne : LayoutRenderer
{
protected override void Append(StringBuilder builder,
LogEventInfo logEvent)
{
builder.AppendFormat($"{GetType().Name} - {logEvent.Level.Name}: {logEvent.Message}");
}
}
[LayoutRenderer("renderer-two")]
class RendererTwo : LayoutRenderer
{
protected override void Append(StringBuilder builder,
LogEventInfo logEvent)
{
builder.AppendFormat($"{GetType().Name} - {logEvent.Level.Name} -> {logEvent.Message}");
}
}
public class TestA
{
private Log _log;
public TestA()
{
LayoutRenderer.Register<RendererOne>("renderer-one");
_log = new Log("${renderer-one}", GetType().Name);
}
[Fact]
public void SomeTest()
{
Loggable l = new Loggable();
l.Info("Test A - SomeTest");
l.Error("Test A - SomeTest");
_log.AssertLogContains("RendererOne - Info: Test A - SomeTest");
_log.AssertLogContains("RendererOne - Error: Test A - SomeTest");
}
[Fact]
public void AnotherTest()
{
Loggable l = new Loggable();
l.Info("Test A - AnotherTest");
l.Error("Test A - AnotherTest");
_log.AssertLogContains("RendererOne - Info: Test A - AnotherTest");
_log.AssertLogContains("RendererOne - Error: Test A - AnotherTest");
}
}
public class TestB
{
private Log _log;
public TestB()
{
LayoutRenderer.Register<RendererTwo>("renderer-two");
_log = new Log("${renderer-two}", GetType().Name);
}
[Fact]
public void SomeTest()
{
Loggable l = new Loggable();
l.Info("Test B - SomeTest");
l.Error("Test B - SomeTest");
_log.AssertLogContains("RendererTwo - Info -> Test B - SomeTest");
_log.AssertLogContains("RendererTwo - Error -> Test B - SomeTest");
}
}
}
请注意,您必须安装此问题的“环境”部分中提到的依赖项库才能运行它。此外,您可能需要多次运行代码才能使代码失败,如上所示。提前谢谢。
答案 0 :(得分:1)
我在GitHub上的NLog问题页面上发布了这个问题(参考:https://github.com/NLog/NLog/issues/2525)。 Rolf建议通过这一行显式禁用Xunit的并行执行:
[assembly: Xunit.CollectionBehavior(DisableTestParallelization = true)]
AssemblyInfo.cs
中的让问题消失了。注意,即使我在XUnit的Visual Studio Runner中明确指出不进行并行运行,也需要在上述环境中使用。