【问题标题】:How to mock Microsoft.Extensions.Logging using Moq如何使用 Moq 模拟 Microsoft.Extensions.Logging
【发布时间】:2019-03-16 16:15:24
【问题描述】:

我目前正在尝试让以下代码在运行时成功:

public delegate void LogDelegate(LogLevel logLevel, EventId eventId, object state, Exception exception, Func<object, Exception, string> formatter);

public abstract class LoggingTestBase
{
    private Mock<ILogger> _mockLogger;

    public ILogger Setup(LogDelegate logCallback)
    {
        _mockLogger = new Mock<ILogger>(MockBehavior.Strict);
        _mockLogger.Setup(logger => logger.Log(
                It.IsAny<LogLevel>(),
                It.IsAny<EventId>(),
                It.IsAny<object>(),
                It.IsAny<Exception>(),
                It.IsAny<Func<object, Exception, string>>()))
            .Callback(logCallback);
        return _mockLogger.Object;
    }
}

问题是,我在运行测试后得到一个MockException,因为被调用的方法是我显然没有设置的通用ILogger.Log&lt;FormattedLogValues&gt;(...)

阅读 existing answer to this 和 Moq 文档后,我得出的结论是,我可能应该只使用正确的类型参数模拟泛型方法,如上所示。

在这里我偶然发现了下一个问题,这使我的想法结束了:

Microsoft.Extensions.Logging 的当前版本中,FormattedLogValues 不再是公共的,而是内部的(在this PR 之后),这使得无法模拟最终调用的通用方法。

有人成功解决了这个问题吗? 怎么样?

【问题讨论】:

    标签: unit-testing logging .net-core mocking moq


    【解决方案1】:

    我也有类似的问题。我只想验证是否调用了对 LogInformation 的调用。据此 -> https://github.com/aspnet/Extensions/issues/1319 应该可以通过起订量解决..

    但是,最后有一个建议是您可以使用 It.IsAnyType 而不是 object.. 对您来说,这将是这样的:

    _mockLogger.Setup(logger => logger.Log(
                It.IsAny<LogLevel>(),
                It.IsAny<EventId>(),
                It.IsAny<It.IsAnyType>(),
                It.IsAny<Exception>(),
                (Func<It.IsAnyType, Exception, string>) It.IsAny<object>()))
            .Callback(logCallback);
    

    我无法让它发挥作用,但也许这会将你推向正确的方向?

    【讨论】:

    【解决方案2】:

    验证解决方案在这里解释和解决:

    https://adamstorr.azurewebsites.net/blog/mocking-ilogger-with-moq , the Github source is here.

    我的个人情况不需要验证,只需要围绕日志调用 Moq。所以我将代码修改为:

    namespace my.xTests
    {
        public static class VerifyLoggingUtil
        {
            public static Mock<ILogger<T>> SetupLogging<T>(
                this Mock<ILogger<T>> logger
            )
            {
                Func<object, Type, bool> state = (v, t) => true;
                logger.Setup(
                    x => x.Log(
                        It.Is<LogLevel>(l => true),
                        It.IsAny<EventId>(),
                        It.Is<It.IsAnyType>((v, t) => state(v, t)),
                        It.IsAny<Exception>(),
                        It.Is<Func<It.IsAnyType, Exception, string>>((v, t) => true)));
                return logger;
            }
        }
    }
    

    在我的 xUnit 测试设置中:

    namespace my.xTests
    {
         public class myTests{
            private Mock<Microsoft.Extensions.Logging.ILogger<sFTPAzFn.Logging>> moqlog;
            private MockRepository mockRepository;
            public myTests(){
                this.mockRepository = new MockRepository(MockBehavior.Strict);
                moqlog = this.mockRepository.Create<Microsoft.Extensions.Logging.ILogger<MyLoggingClass>>();
            }
            private IInterfaceUnderTest CreateService(){
                 var moqlogobject = moqlog.SetupLogging<MyLoggingClass>().Object;
                 return new ClassUnderTest(moqlogobject);
            }
         }
    }
    

    【讨论】:

      猜你喜欢
      • 2012-03-18
      • 2010-10-19
      • 2016-09-30
      • 2019-10-06
      • 1970-01-01
      • 2020-10-27
      • 2012-06-01
      • 2018-12-27
      • 2019-06-16
      相关资源
      最近更新 更多