You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Mock ILogger及验证方法调用时遇到的异常问题

解决Moq验证ILogger.LogError时的NotSupportedException问题

问题根源

你遇到的错误核心原因是:你调用的LogError是静态扩展方法,而非ILogger<T>接口的原生实例方法。

ILogger<T>接口本身只定义了Log()这一个实例方法,所有LogError、LogInformation等常用日志方法,都是Microsoft.Extensions.Logging.LoggerExtensions类提供的静态扩展方法。Moq只能Mock/验证接口的原生实例成员,无法处理静态扩展方法,因此会抛出"方法不属于被Mock对象"或"非虚拟成员验证无效"的错误。

解决方案

直接针对ILogger<T>的原生Log()方法进行验证,因为所有扩展方法最终都会调用这个底层方法。

修改后的测试代码如下:

[Fact]
public void Log_error_should_call_logger_error_method()
{
    // Arrange
    var applicationException = new ApplicationException("This is a mocked exception");
    var exceptionHandlerFeatureMock = ErrorsControllerGenerator.GenerateExceptionHandlerFeatureMock(applicationException);
    var loggerMock = new Mock<ILogger<ErrorsController>>();
    // 注意:这里要传入Mock的实例对象,而非Mock本身
    var sut = ErrorsControllerGenerator.GenerateErrorsController(exceptionHandlerFeatureMock, loggerMock.Object);

    var testErrorMessage = "This is a test error";

    // Act
    sut.LogError(testErrorMessage);

    // Assert
    loggerMock.Verify(logger => logger.Log(
        // 匹配Error级别
        LogLevel.Error,
        // 事件ID可以是任意值
        It.IsAny<EventId>(),
        // 匹配包含目标消息的日志内容(扩展方法会包装消息成结构化对象)
        It.Is<It.IsAnyType>((state, type) => state.ToString().Contains(testErrorMessage)),
        // 本次调用无异常,匹配任意值
        It.IsAny<Exception>(),
        // 日志消息格式化委托,匹配任意值
        It.IsAny<Func<It.IsAnyType, Exception, string>>()),
        // 验证调用次数
        Times.Once);
}

关键说明

  1. 为何验证Log()方法:所有LogXxx扩展方法都会将调用转发给Log(),并传入对应的LogLevel、结构化状态等参数,验证这个方法就能确认日志是否被正确触发。
  2. 状态对象匹配逻辑:扩展方法会把日志消息包装成内部结构化对象,因此不能直接匹配字符串,需通过It.IsAnyType结合ToString()检查是否包含目标消息。
  3. Mock实例传递:确保传给控制器的是loggerMock.Object(Mock生成的接口实例),而非loggerMock本身,否则控制器无法正确注入ILogger实例。

内容的提问来源于stack exchange,提问作者Pablo52

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 12:20:39