我有一个接收ILogger的类,我想模拟LogInformation调用,但这是一个扩展方法。如何对此进行适当的设置调用?
发布于 2019-10-16 20:55:01
如果你使用的是Moq >= 4.13,这里有一种模拟ILogger的方法
logger.Verify(x => x.Log(
It.IsAny<LogLevel>(),
It.IsAny<EventId>(),
It.IsAny<It.IsAnyType>(),
It.IsAny<Exception>(),
(Func<It.IsAnyType, Exception, string>)It.IsAny<object>()));您可以更具体地更改It.IsAny<LogLevel>()、It.IsAny<EventId>()和It.IsAny<Exception>()存根,但必须使用It.IsAnyType,因为FormattedLogValues现在是internal。
参考:TState in ILogger.Log used to be object, now FormattedLogValues
发布于 2020-09-02 16:49:29
带有回调的示例,使用Moq 4.14.5测试。此Github Issue上提供了更多信息
PM>安装-软件包模式
var logger = new Mock<ILogger<ReplaceWithYourObject>>();
logger.Setup(x => x.Log(
It.IsAny<LogLevel>(),
It.IsAny<EventId>(),
It.IsAny<It.IsAnyType>(),
It.IsAny<Exception>(),
(Func<It.IsAnyType, Exception, string>)It.IsAny<object>()))
.Callback(new InvocationAction(invocation =>
{
var logLevel = (LogLevel)invocation.Arguments[0]; // The first two will always be whatever is specified in the setup above
var eventId = (EventId)invocation.Arguments[1]; // so I'm not sure you would ever want to actually use them
var state = invocation.Arguments[2];
var exception = (Exception)invocation.Arguments[3];
var formatter = invocation.Arguments[4];
var invokeMethod = formatter.GetType().GetMethod("Invoke");
var logMessage = (string)invokeMethod?.Invoke(formatter, new[] { state, exception });
}));一个完整的UnitTesting泛型助手类
public static class LoggerHelper
{
public static Mock<ILogger<T>> GetLogger<T>()
{
var logger = new Mock<ILogger<T>>();
logger.Setup(x => x.Log(
It.IsAny<LogLevel>(),
It.IsAny<EventId>(),
It.IsAny<It.IsAnyType>(),
It.IsAny<Exception>(),
(Func<It.IsAnyType, Exception, string>)It.IsAny<object>()))
.Callback(new InvocationAction(invocation =>
{
var logLevel = (LogLevel)invocation.Arguments[0]; // The first two will always be whatever is specified in the setup above
var eventId = (EventId)invocation.Arguments[1]; // so I'm not sure you would ever want to actually use them
var state = invocation.Arguments[2];
var exception = (Exception)invocation.Arguments[3];
var formatter = invocation.Arguments[4];
var invokeMethod = formatter.GetType().GetMethod("Invoke");
var logMessage = (string)invokeMethod?.Invoke(formatter, new[] { state, exception });
Trace.WriteLine($"{logLevel} - {logMessage}");
}));
return logger;
}
}发布于 2018-10-10 20:41:09
通常通过扩展方法、LogWarning、LogError等使用ILogger。
在我的例子中,我感兴趣的是LogWarning方法,在查看代码之后,它将调用ILogger中的Log方法。为了用Moq模拟它,这就是我最终要做的:
var list = new List<string>();
var logger = new Mock<ILogger>();
logger
.Setup(l => l.Log<FormattedLogValues>(LogLevel.Warning, It.IsAny<EventId>(), It.IsAny<FormattedLogValues>(), It.IsAny<Exception>(), It.IsAny<Func<FormattedLogValues, Exception, string>>()))
.Callback(
delegate (LogLevel logLevel, EventId eventId, FormattedLogValues state, Exception exception, Func<FormattedLogValues, Exception, string> formatter)
{
list.Add(state.ToString());
});在较新版本的.NET Core3.0中,这将不起作用。因为FormattedLogValues是一个内部类型。您需要将moq版本至少更新为:
`<PackageReference Include="Moq" Version="4.16.0" />`更新Moq后,解决方法如下所示:
var log = new List<string>();
var mockLogger = new Mock<ILogger>();
mockLogger.Setup(
l => l.Log(
It.IsAny<LogLevel>(),
It.IsAny<EventId>(),
It.IsAny<It.IsAnyType>(),
It.IsAny<Exception>(),
(Func<It.IsAnyType, Exception, string>)It.IsAny<object>()))
.Callback((IInvocation invocation) =>
{
var logLevel = (LogLevel)invocation.Arguments[0];
var eventId = (EventId)invocation.Arguments[1];
var state = (IReadOnlyCollection<KeyValuePair<string, object>>)invocation.Arguments[2];
var exception = invocation.Arguments[3] as Exception;
var formatter = invocation.Arguments[4] as Delegate;
var formatterStr = formatter.DynamicInvoke(state, exception);
log.Add(
$"{logLevel} - {eventId.Id} - Testing - {formatterStr}");
});注意特殊的类型转换:(Func<It.IsAnyType, Exception, string>)It.IsAny<object>())和处理参数的IInvocation。
https://stackoverflow.com/questions/52707702
复制相似问题