Microsoft.Extensions.Logging.Abstractions更新后,Moq和Microsoft.Extensions.Logging.ILogger单元测试失败

时间:2020-05-11 20:37:45

标签: unit-testing asp.net-core moq ilogger

将Microsoft.Extensions.Logging.Abstractions从Version = 2.0.0.0更新到Version = 3.1.1.0后,我的某些单元测试失败。

我模拟了一个ILogger:

<INPUT id=TBPRODDESC33333 value=0 name=TBPRODDESC33333 InStock="5">

已经建立了一个验证对Log()的调用的单元:

var loggerMock = new Mock<ILogger<BillingEventProcessor>>();            
loggerMock.Setup(l => l.Log(
It.IsAny<LogLevel>(), 
It.IsAny<EventId>(), 
It.IsAny<IReadOnlyList<KeyValuePair<string, object>>>(), 
It.IsAny<Exception>(), 
It.IsAny<Func<object, Exception, string>>()));

在更新之前,logger.Verify(l => l.Log( It.IsAny<LogLevel>(), It.IsAny<EventId>(), It.IsAny<IReadOnlyList<KeyValuePair<string, object>>>(), It.IsAny<Exception>(), It.IsAny<Func<object, Exception, string>>()) ); 类型为IReadOnlyList<KeyValuePair<string, object>>类型。

在v2中,FormattedLogValues是一个公共类,但在v3.1.1中,FormattedLogValues是一个内部只读结构。这种变化似乎与测试失败有关。

我尝试将It.IsAny用作第三个参数,而不是IReadOnlyList或FormattedLogValues,但我对此没有任何运气。

谁知道我可以如何更改此测试代码以使测试通过?从调试信息中可以看到,对Log方法的调用按预期进行,只是无法弄清楚如何使用内部readonly struct参数正确设置这些模拟。

这是一个.NET Core 2.2项目。

1 个答案:

答案 0 :(得分:0)

.NET Core 3. *中的

FormattedLogValues已更改为internal,这有点不方便。使用Moq的常见解决方案是使用It.IsAnyType

loggerMock.Verify(l => l.Log(
    It.IsAny<LogLevel>(),
    It.IsAny<EventId>(),
    It.IsAny<It.IsAnyType>(),
    It.IsAny<Exception>(),
    (Func<It.IsAnyType, Exception, string>)It.IsAny<object>()),
  Times.Once);

我通常希望从验证中获得更多信息,至少检查一下消息:

loggerMock.Verify(l => l.Log(
    It.IsAny<LogLevel>(),
    It.IsAny<EventId>(),
    It.Is<It.IsAnyType>((o, t) => ((IReadOnlyList<KeyValuePair<string, object>>)o).Last().Value.ToString().Equals(message)),
    It.IsAny<Exception>(),
    (Func<It.IsAnyType, Exception, string>)It.IsAny<object>()),
  Times.Once);

作为旁注,您提到您正在设置记录器模拟。我想不起来我明确设置了记录器模拟程序的时间,因为通常没有任何必要。

最后,如果您像我一样经常在无头的黑匣子中这样做,请考虑使用contrib库Moq.Contrib.ExpressionBuilders.Logging,它可以解决上述所有问题,并提供流利的构建器以轻松创建verify表达式。免责声明,我是作者。