更新Microsoft.Extensions.Logging.Abstractions后,Moq和Microsoft.E



将Microsoft.Extension.Loggin.Abstractions从2.0.0.0版本更新到3.1.1.0版本后,我的一些单元测试失败。

我有一个ILogger被嘲笑为:

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>>()));

还有一个单元可以验证是否调用了Log((:

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>>类型为FormattedLogValues类型。

在v2中,FormattedLogValues是一个公共类,但在v3.1.1中,FormatedLogValues却是一个内部只读结构。此更改似乎与测试失败有关。

我试过用It.IsAny代替IReadOnlyList或FormattedLogValues作为第三个参数,但我运气不好。

有人知道我如何修改这个测试代码以使测试通过吗?我可以从调试信息中看到,对Log方法的调用是按预期进行的,我只是不知道如何使用内部只读结构参数正确设置这些mock。

这是一个.NET Core 2.2项目。

.NET Core 3.*中的FormattedLogValues被更改为内部,这有点不方便。使用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);

作为附带说明,您提到您正在设置记录器mock。我想不出有什么时候我明确地设置了一个记录器模拟,因为通常没有任何必要。

最后,如果你像我一样做这件事,通常是在无头黑框中,可以考虑contrib库Moq.Contrrib.ExpressionBuilders.Logging,它可以处理以上所有内容,并提供一个流畅的生成器来轻松创建验证表达式。免责声明,我是作者。

最新更新