.net core 2.0 ConfigureLogging xunit测试
.net core 2.0 ConfigureLogging xunit test
在我的 .NET Core 2.0 项目的 xUnit 集成测试中,我在终端中看不到日志消息也打印了测试结果。当代码在 WebHost 环境中为 运行 时,日志将打印到控制台。
这是我在测试构造函数中配置日志记录的方式:
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");
但是我没有看到任何日志消息。
xUnit 在版本 2 中发生了变化,不再为测试捕获标准输出:
If you used xUnit.net 1.x, you may have previously been writing output to Console
, Debug
, or Trace
. When xUnit.net v2 shipped with parallelization turned on by default, this output capture mechanism was no longer appropriate; it is impossible to know which of the many tests that could be running in parallel were responsible for writing to those shared resources.
相反,您现在应该使用 an explicit mechanism 写入测试输出。基本上,您不是写入控制台,而是写入一个特殊的 ITestOutputHelper
.
当然,ASP.NET 核心日志记录默认不支持这种输出机制。幸运的是,为测试输出编写日志记录提供程序并不太困难。我刚刚实施了一个快速提供程序并将其包含在下面的回答中。你可以这样使用它:
public class Example
{
private readonly ILogger<Example> _logger;
public Example(ITestOutputHelper testOutputHelper)
{
var loggerFactory = LoggerFactory.Create(l =>
{
l.AddProvider(new XunitLoggerProvider(testOutputHelper));
});
_logger = loggerFactory.CreateLogger<Example>();
}
[Fact]
public void Test()
{
_logger.LogDebug("Foo bar baz");
}
}
请注意,通常应避免在单元测试中创建完整的依赖注入容器。在单元测试中使用 DI 通常表明您的单元测试不是 unit 测试,而是集成测试。在单元测试中,您应该只测试一个特定的单元并显式地传递它的所有依赖项——通常只是作为一个模拟。正如你在上面的例子中看到的,创建一个记录器实际上是一件非常简单的事情,不需要 DI。
正如所承诺的,这是 XunitLoggerProvider
和 XunitLogger
,您需要 运行 上面显示的代码,并将 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 readonly NoopDisposable Instance = new NoopDisposable();
public void Dispose()
{ }
}
}
在我的 .NET Core 2.0 项目的 xUnit 集成测试中,我在终端中看不到日志消息也打印了测试结果。当代码在 WebHost 环境中为 运行 时,日志将打印到控制台。
这是我在测试构造函数中配置日志记录的方式:
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");
但是我没有看到任何日志消息。
xUnit 在版本 2 中发生了变化,不再为测试捕获标准输出:
If you used xUnit.net 1.x, you may have previously been writing output to
Console
,Debug
, orTrace
. When xUnit.net v2 shipped with parallelization turned on by default, this output capture mechanism was no longer appropriate; it is impossible to know which of the many tests that could be running in parallel were responsible for writing to those shared resources.
相反,您现在应该使用 an explicit mechanism 写入测试输出。基本上,您不是写入控制台,而是写入一个特殊的 ITestOutputHelper
.
当然,ASP.NET 核心日志记录默认不支持这种输出机制。幸运的是,为测试输出编写日志记录提供程序并不太困难。我刚刚实施了一个快速提供程序并将其包含在下面的回答中。你可以这样使用它:
public class Example
{
private readonly ILogger<Example> _logger;
public Example(ITestOutputHelper testOutputHelper)
{
var loggerFactory = LoggerFactory.Create(l =>
{
l.AddProvider(new XunitLoggerProvider(testOutputHelper));
});
_logger = loggerFactory.CreateLogger<Example>();
}
[Fact]
public void Test()
{
_logger.LogDebug("Foo bar baz");
}
}
请注意,通常应避免在单元测试中创建完整的依赖注入容器。在单元测试中使用 DI 通常表明您的单元测试不是 unit 测试,而是集成测试。在单元测试中,您应该只测试一个特定的单元并显式地传递它的所有依赖项——通常只是作为一个模拟。正如你在上面的例子中看到的,创建一个记录器实际上是一件非常简单的事情,不需要 DI。
正如所承诺的,这是 XunitLoggerProvider
和 XunitLogger
,您需要 运行 上面显示的代码,并将 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 readonly NoopDisposable Instance = new NoopDisposable();
public void Dispose()
{ }
}
}