首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何模拟ILogger LogInformation

如何模拟ILogger LogInformation
EN

Stack Overflow用户
提问于 2018-10-09 01:55:07
回答 7查看 13.6K关注 0票数 32

我有一个接收ILogger的类,我想模拟LogInformation调用,但这是一个扩展方法。如何对此进行适当的设置调用?

EN

回答 7

Stack Overflow用户

发布于 2019-10-16 20:55:01

如果你使用的是Moq >= 4.13,这里有一种模拟ILogger的方法

代码语言:javascript
复制
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

票数 30
EN

Stack Overflow用户

发布于 2020-09-02 16:49:29

带有回调的示例,使用Moq 4.14.5测试。此Github Issue上提供了更多信息

PM>安装-软件包模式

代码语言:javascript
复制
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泛型助手类

代码语言:javascript
复制
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;
    }
}
票数 21
EN

Stack Overflow用户

发布于 2018-10-10 20:41:09

通常通过扩展方法、LogWarning、LogError等使用ILogger。

在我的例子中,我感兴趣的是LogWarning方法,在查看代码之后,它将调用ILogger中的Log方法。为了用Moq模拟它,这就是我最终要做的:

代码语言:javascript
复制
     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版本至少更新为:

代码语言:javascript
复制
`<PackageReference Include="Moq" Version="4.16.0" />`

更新Moq后,解决方法如下所示:

代码语言:javascript
复制
            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。

票数 8
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/52707702

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档