简体   繁体   English

.net core 2.0 ConfigureLogging xunit test

[英].net core 2.0 ConfigureLogging xunit test

In my xUnit integration test in my .NET Core 2.0 project I cannot see log messages in the terminal that also prints the test results. 在我的.NET Core 2.0项目中的xUnit集成测试中,我无法在终端中看到同时打印测试结果的日志消息。 When the code is run in WebHost environment, the logs are printed out to the console. 在WebHost环境中运行代码时,日志将打印到控制台。

This is how I configure logging in the test's constructor: 这是我在测试构造函数中配置日志记录的方法:

var config = new ConfigurationBuilder()
    .AddJsonFile("appsettings.Tests.json")
    .Build();

var services = new ServiceCollection();

services.AddLogging(options => {
    options.AddConfiguration(config.GetSection("Logging"));
    options.AddConsole();
    options.AddDebug();
});

var serviceProvider = services.BuildServiceProvider();
var loggerFactory = serviceProvider.GetService<ILoggerFactory>();
var logger = loggerFactory.CreateLogger("Test");
logger.LogError("From ctor");

But I don't see any log message. 但我没有看到任何日志消息。

xUnit has changed in version 2 to no longer capture the standard output for tests: xUnit在版本2中已更改为不再捕获测试的标准输出:

If you used xUnit.net 1.x, you may have previously been writing output to Console , Debug , or Trace . 如果您使用xUnit.net 1.x,则可能以前一直在将输出写入ConsoleDebugTrace When xUnit.net v2 shipped with parallelization turned on by default, this output capture mechanism was no longer appropriate; 当xUnit.net v2默认启用并行化时,此输出捕获机制不再合适; it is impossible to know which of the many tests that could be running in parallel were responsible for writing to those shared resources. 不可能知道可以并行运行的许多测试中的哪一个负责写入这些共享资源。

Instead, you are now supposed to use an explicit mechanism to write to the test output. 相反,您现在应该使用显式机制来写入测试输出。 Basically, instead of writing to the console, you are writing to a special ITestOutputHelper . 基本上,您不是写入控制台,而是写入特殊的ITestOutputHelper

Of course, this output mechanism is not supported by default with ASP.NET Core logging. 当然,ASP.NET核心日志记录默认不支持此输出机制。 Fortunately, writing a logging provider for the test output isn't too difficult. 幸运的是,为测试输出编写日志记录提供程序并不困难。 I've just implemented a quick provider and included it in my answer below. 我刚刚实现了一个快速提供程序,并在下面的答案中包含它。 You can use it like this: 你可以像这样使用它:

public class Example
{
    private readonly ILogger<Example> _logger;

    public Example(ITestOutputHelper testOutputHelper)
    {
        var loggerFactory = new LoggerFactory();
        loggerFactory.AddProvider(new XunitLoggerProvider(testOutputHelper));
        _logger = loggerFactory.CreateLogger<Example>();
    }

    [Fact]
    public void Test()
    {
        _logger.LogDebug("Foo bar baz");
    }
}

Note that you usually should avoid creating a complete dependency injection container in unit tests. 请注意,通常应避免在单元测试中创建完整的依赖注入容器。 Having DI in unit tests is usually a sign that your unit test is not a unit test but instead an integration test. 在单元测试中使用DI通常表明您的单元测试不是单元测试,而是集成测试。 In a unit test, you should only test one particular unit and pass all its dependencies explicitly—more than often just as a mock. 在单元测试中,您应该只测试一个特定单元并明确地传递其所有依赖项 - 而不仅仅是作为模拟。 As you can see in the example above, creating a logger is actually a very simple thing to do without DI. 正如您在上面的示例中所看到的,创建记录器实际上是一个非常简单的事情,没有DI。


As promised, this is the XunitLoggerProvider and the XunitLogger which you need to run the code shown above, and to integrate the Microsoft.Extensions.Logging framework with xUnit test output: 正如所承诺的,这是运行上面显示的代码所需的XunitLoggerProviderXunitLogger ,以及将Microsoft.Extensions.Logging框架与xUnit测试输出集成:

public class XunitLoggerProvider : ILoggerProvider
{
    private readonly ITestOutputHelper _testOutputHelper;

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

    public ILogger CreateLogger(string categoryName)
        => new XunitLogger(_testOutputHelper, categoryName);

    public void Dispose()
    { }
}

public class XunitLogger : ILogger
{
    private readonly ITestOutputHelper _testOutputHelper;
    private readonly string _categoryName;

    public XunitLogger(ITestOutputHelper testOutputHelper, string categoryName)
    {
        _testOutputHelper = testOutputHelper;
        _categoryName = categoryName;
    }

    public IDisposable BeginScope<TState>(TState state)
        => NoopDisposable.Instance;

    public bool IsEnabled(LogLevel logLevel)
        => true;

    public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
    {
        _testOutputHelper.WriteLine($"{_categoryName} [{eventId}] {formatter(state, exception)}");
        if (exception != null)
            _testOutputHelper.WriteLine(exception.ToString());
    }

    private class NoopDisposable : IDisposable
    {
        public static NoopDisposable Instance = new NoopDisposable();
        public void Dispose()
        { }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM