Moq和Microsoft.Extensions.Logging.ILogger单元测试在Microsoft.Extensions.Logging.Abstractions更新后失败 [英] Moq and Microsoft.Extensions.Logging.ILogger unit tests failing after Microsoft.Extensions.Logging.Abstractions update

查看:85
本文介绍了Moq和Microsoft.Extensions.Logging.ILogger单元测试在Microsoft.Extensions.Logging.Abstractions更新后失败的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Some of my unit tests are failing after updating Microsoft.Extensions.Logging.Abstractions from Version=2.0.0.0 to Version=3.1.1.0.

我模拟了一个ILogger:

I have an ILogger mocked as so:

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()的调用的单元:

And a unit that verifies a call to Log() has been made:

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<字符串,对象>> 类型的类型为 FormattedLogValues .

Prior to updating, the IReadOnlyList<KeyValuePair<string, object>> type was of type FormattedLogValues.

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

In v2, FormattedLogValues was a public class but in v3.1.1, FormattedLogValues is an internal readonly struct. This change appears to be related to the test failures.

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

I've tried using It.IsAny for that 3rd parameter instead of the IReadOnlyList or FormattedLogValues but I didn't have any luck with that.

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

Anyone know how I can alter this test code to make the test pass? I can see from debugging info that a call to the Log method is made as expected, I just can't figure out how to set up these mocks correctly with the internal readonly struct parameter.

这是一个.NET Core 2.2项目.

This is a .NET Core 2.2 project.

推荐答案

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

FormattedLogValues in .NET Core 3.* was changed to internal which is a bit inconvenient. The common solution using Moq is to use 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);

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

I usually like to get a bit more out of my verify, checking the message at least:

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

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

As a side note you mentioned you're setting up the logger mock. I can't think of a time where I've explicitly set up a logger mock as there usually isn't any need to.

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

Finally if you're doing this a lot like I do, usually in headless black boxes, consider the contrib library Moq.Contrib.ExpressionBuilders.Logging which takes care of all of the above and provides a fluent builder to easily create the verify expression. Disclaimer, I am the author.

这篇关于Moq和Microsoft.Extensions.Logging.ILogger单元测试在Microsoft.Extensions.Logging.Abstractions更新后失败的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆