Mock Microsoft.Extensions.Logging.ILogger

ILogger 已经成了 Asp.net core 和 azure function里面默认的Logger了。 但是它的一些调用方法是扩展方法 是放在 Microsoft.Extensions.Logging.LoggerExtensions 里面的。 对于扩展方法我们是没有办法直接Mock的。 所以我们得去Mock它的 Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter) 方法

using Microsoft.Extensions.Logging;
using Moq;
using System;
using System.Collections.Generic;

namespace Xunit
{
    public class LogMockInfo
    {
        public LogLevel Level { get; set; }

        public EventId EventId { get; set; }

        public IReadOnlyCollection<KeyValuePair<string, object>> State { get; set; }

        public Exception Exception { get; set; }
    }

    public static class LogMockHelper
    {
        public static Mock<ILogger> Get(LogMockInfo info)
        {
            var msLogger = new Mock<Microsoft.Extensions.Logging.ILogger>();
            msLogger.Setup(x => x.IsEnabled(It.IsAny<LogLevel>())).Returns(true)
                .Callback<LogLevel>(x =>
                {
                });
            msLogger.Setup(it => it.Log<It.IsAnyType>(It.IsAny<LogLevel>(),
                It.IsAny<EventId>(),
                It.IsAny<It.IsAnyType>(),
                It.IsAny<Exception>(),
                It.IsAny<Func<It.IsAnyType, Exception, string>>()))
                .Callback((IInvocation invocation) =>
                {
                    info.Level = (LogLevel)invocation.Arguments[0];
                    info.EventId = (EventId)invocation.Arguments[1];
                    info.State = (IReadOnlyCollection<KeyValuePair<string, object>>)invocation.Arguments[2];
                    info.Exception = invocation.Arguments[3] as Exception;
                    var formatter = invocation.Arguments[4] as Delegate;
                    var formatterStr = formatter.DynamicInvoke(info.State, info.Exception);
                });
            return msLogger;
        }
    }
}

测试代码

using Microsoft.Extensions.Logging;
using System;
using Xunit;

namespace MyFirstUnitTests
{
    public class LogTest
    {
        [Fact]
        public void Log_Test_Example()
        {
            var logInfo = new LogMockInfo();
            var msLogger = LogMockHelper.Get(logInfo);

            var exception = new FormatException();
            msLogger.Object.IsEnabled(LogLevel.Debug);
            msLogger.Object.LogError(exception, "abc");
            Assert.Equal(LogLevel.Error, logInfo.Level);
            Assert.Equal(exception, (FormatException)logInfo.Exception);
        }
    }
}

我们这个LogMockHelper支持的版本是5.0.0,旧版本或者新版本,泛型的类型可能不一样。

5.0.0的调用方式是 logger.Log<FormattedLogValues>(logLevel, eventId, new FormattedLogValues(message, args), exception, LoggerExtensions._messageFormatter); 然后这个FormattedLogValues 是internal级别的。 我们访问不到它。 还好是Moq有提供了一个类型 It.IsAnyType

上一篇:Mock dbcontext
最近更新的
...