如何解决Moq验证升级到.NET Core 3.1后无法按预期工作
顾名思义,这在.NET Core 2.2和Moq版本4.10.1中对我们有用。升级到.NET Core 3.1和Moq版本4.14.5后,verify方法将失败,表明尚未调用指定的方法(未对基础代码进行任何更改)。我将Moq回滚到4.10.1版本,只是为了查看是否是由于Moq新版本中的更改所致。我仍然遇到相同的错误。
尝试验证是否已将日志消息写入ILogger。
奇怪的是,如果我调试单元测试并使用变量表查看模拟对象,则表明该方法确实已被调用。
相关代码:
public class AuditFilter,IResultFilter
{
...
public void OnResultExecuted( ResultExecutedContext context )
{
if( !IsContextValid( context ) )
{ return; }
...
}
public override bool IsContextValid( FilterContext context )
{
if( context == null )
{
Logger.Error( "Error writing to the audit log",new ArgumentNullException( nameof( context ) ) );
return false;
}
if( context.HttpContext == null )
{
Logger.LogError( "Error writing to the audit log",new ArgumentNullException( nameof( context.HttpContext ) ) );
return false;
}
return true;
}
public ILogger Logger { get; set; }
...
}
public class AuditTests : BaseTests
{
...
private Mock<ILogger> _mockLog;
private AuditFilter _filter;
[SetUp]
public void Setup()
{
_mockLog = new Mock<Microsoft.Extensions.Logging.ILogger>();
_mockLog.SetupAllProperties;
_filter = new AuditFilter();
}
[Test]
public void Service_Filters_Audit_IsContextValid_Context_Null()
{
var expected = false;
_filter.Logger = _mockLog.Object;
var actual = _filter.IsContextValid( null );
_mockLog.Verify( logger => logger.Log( LogLevel.Error,It.IsAny<EventId>(),It.IsAny<object>(),It.IsAny<ArgumentNullException>(),It.IsAny<Func<object,Exception,string>>() ),Times.Once );
Assert.AreEqual( expected,actual );
}
...
}
注意::方法ILogger.LogError是Microsoft的ILogger扩展方法,它调用ILogger.Log方法。
注意::一个整数隐式转换为Microsoft.Extensions.Logging.EventId,这是ILogger.Log方法的第二个输入参数类型。
这些签名似乎与我匹配;所以我不确定为什么会说它没有被调用。
重申一下,此代码在升级到.NET Core 3.1之前有效,并且仍在我们预先创建的代码中有效。
此外,在有人建议需要设置该方法之前:没有该方法,它在升级之前就可以使用,而我已经尝试过了,但是没有用。
解决方法
我相信问题将是验证表达式的这一部分
It.IsAny<Func<object,Exception,string>>()
在幕后,它不是Func<object,string>
,并且由于这种区别,模拟的IsAny匹配器不匹配。如果将其修改为
(Func<object,string>) It.IsAny<object>()
它应该匹配。以下是我确定的验证表达式的起点,因为它至少适用于.NET Core 2. *以上版本:
loggerMock.Verify(x => x.Log(
It.IsAny<LogLevel>(),It.IsAny<EventId>(),It.IsAny<IReadOnlyList<KeyValuePair<string,object>>>(),It.IsAny<Exception>(),(Func<object,string>) It.IsAny<object>()),Times.Exactly(expectedNumberOfInvocations));
您可以将It.IsAny<object>()
用作第三个参数,但是我发现在查询属性时这样做更方便。
最近,我一直在为黑匣子流程进行相当多的日志调用验证,因此现在我大多使用Moq.Contrib.ExpressionBuilders.Logging来构建流畅,可读的验证表达式。免责声明:我是作者。
,就像我在注释中添加的一样,这是一个known issue,带有Moq和.NET Core,直接来自.NET Core 3.0的预览版。请查看github问题,以了解为什么此更新失败了。
简而言之,从链接的问题来看,这里的失败是由于以下事实导致的:传递给Logger.Log
方法的类型现在已更改为FormattedLogValues
。尽管Moq 4.13.0中引入了通用类型匹配器It.IsAnyType
,但这不能解决该问题。
这样做的原因是Moq states here
的作者之一(到目前为止)重要的一点是,
It.IsAnyType
类型参数中的嵌套位置未使用It.IsAny<>
。
作为解决方法,我们应该替换
It.IsAny<Func<object,string>>()
与
(Func<object,string>)It.IsAny<object>()
为此提供的理由是提高类型匹配器的性能,因为前者将导致引擎盖下的所有类型参数分解,从而首先查看是否包含类型匹配器。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。