Как протестировать встроенный ядро asp.net
Я хочу проверить, что некоторые журналы зарегистрированы. Я использую встроенный ядро asp.net, встроенный в ILogger, и вставляю его с встроенным DI-сервером asp.net:
private readonly ILogger<InvoiceApi> _logger;
public InvoiceApi(ILogger<InvoiceApi> logger)
{
_logger = logger;
}
то я использую его как: _logger.LogError("error));
Я попытался издеваться над ним (с moq), как обычно:
MockLogger = new Mock<ILogger<InvoiceApi>>();
и введите это в службу для тестирования:
new InvoiceApi(MockLogger.Object);
затем попробовал проверить:
MockLogger.Verify(m => m.LogError(It.Is<string>(s => s.Contains("CreateInvoiceFailed"))));
но он бросает:
Неверная проверка для не виртуального (переопределяемого в VB) члена: m = > m.LogError
Итак, как я могу проверить эти журналы?
Ответы
Ответ 1
Как уже сказал @Nkosi, нельзя издеваться над методом расширения. Что вы должны высмеивать, так это метод ILogger.Log
, который LogError
вызывает в. Это делает код проверки немного неуклюжим, но он должен работать:
MockLogger.Verify(
m => m.Log(
LogLevel.Error,
It.IsAny<EventId>(),
It.Is<FormattedLogValues>(v => v.ToString().Contains("CreateInvoiceFailed")),
It.IsAny<Exception>(),
It.IsAny<Func<object, Exception, string>>()
)
);
(не уверен, что это скомпилируется, но вы понимаете суть)
Ответ 2
Я написал короткую статью, в которой показаны различные подходы, в том числе насмешка над базовым методом Log(), как описано в других ответах здесь. Статья включает в себя полное репозиторий GitHub с каждым из различных вариантов. В конце я рекомендую использовать собственный адаптер, а не работать напрямую с типом ILogger, если вам нужно проверить, вызывается ли он.
https://ardalis.com/testing-logging-in-aspnet-core
Ответ 3
LogError
- это метод расширения (статический), а не метод экземпляра. Вы не можете "напрямую" имитировать статические методы (следовательно, метод расширения) с издевательской структурой, поэтому Moq не может издеваться и, следовательно, проверять этот метод. Я видел предложения в Интернете об адаптации/упаковке целевого интерфейса и выполнении ваших макетов, но это означало бы перезаписывать, если вы использовали стандартный ILogger
по всему вашему коду во многих местах. Вам нужно было бы создать 2 новых типа, один для класса-оболочки, а другой для макетируемого интерфейса.