.net core 2.0 ConfigureLogging xUnit test


В моем тесте интеграции xUnit в моем проекте .NET Core 2.0 я не вижу сообщений журнала в терминале, который также печатает результаты теста. Когда код выполняется в среде 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");

Но я не вижу никакого сообщения журнала.

1   7   2017-09-12 09:15:40

1 ответ:

XUnit изменился в версии 2, чтобы больше не захватывать стандартный вывод для тестов:

Если вы использовали xUnit.net 1.x, возможно, вы ранее писали вывод на Console, Debug, или Trace. Когда xUnit.net в версии v2, поставляемой с включенным по умолчанию распараллеливанием, этот механизм захвата выходных данных больше не был уместен; невозможно узнать, какие из множества тестов, которые могли бы выполняться параллельно, отвечали за запись в эти общие файлы. ресурсы.

Вместо этого теперь предполагается использоватьявный механизм для записи в тестовый вывод. В принципе, вместо того, чтобы писать на консоль, вы пишете на специальный ITestOutputHelper.

Конечно, этот механизм вывода не поддерживается по умолчанию с ASP.NET ведение журнала ядра. К счастью, написать регистратор для вывода теста не слишком сложно. Я только что реализовал быстрый поставщик и включил его в свой ответ ниже. Вы можете использовать его как это:

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");
    }
}

Обратите внимание, что обычно следует избегать создания полного контейнера инъекции зависимостей в модульных тестах. Наличие 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 NoopDisposable Instance = new NoopDisposable();
        public void Dispose()
        { }
    }
}