使用最小起订量中的任何结构参数验证方法调用



将我的应用程序从 ASP.NET Core 2.2迁移到 ASP.NET Core 3.0时,我遇到了以下问题:

我有一个类,在某些情况下应该记录错误消息。这是通过在ILogger<MyClass>上调用LogError来完成的。

我曾经用我的单元测试中的以下代码片段来验证这一点:

Mock<ILogger<MyClass>> loggerMock = ...;
MyClass myClass = ...;
myClass.MethodThatLogsTestException();
loggerMock.Verify(l => l.Log(
It.IsAny<LogLevel>(),
It.IsAny<EventId>(),
It.IsAny<object>(),
It.IsAny<TestException>(),
It.IsAny<Func<object, Exception, string>>())
);

现在问题来了:

在 ASP.NET Core 2.2中,第三个参数(通过It.IsAny<object>()模拟(是内部类型FormattedLogValues。这是一堂课,所以It.IsAny<object>()工作。在 ASP.NET Core 3.0中,它被更改为结构体,因此It.IsAny<object>()不再匹配它。

如何让我的Verify()调用在 ASP.NET Core 3.0中工作?是否有与任何结构类型匹配的It.IsAny()版本?

编辑: 这是一个完全可运行的代码片段,在 ASP.NET Core 3.0 上失败,在 Core 2.2 ASP.NET 成功。

public class Test
{
public class Impl
{
private readonly ILogger<Impl> logger;
public Impl(ILogger<Impl> logger)
{
this.logger = logger;
}
public void Method()
{
logger.LogError(new Exception(), "An error occurred.");
}
}
[Fact]
public void LogsErrorOnException()
{
var loggerMock = new Mock<ILogger<Impl>>();
var sut = new Impl(loggerMock.Object);
sut.Method();
loggerMock.Verify(l => l.Log(
It.IsAny<LogLevel>(),
It.IsAny<EventId>(),
It.IsAny<object>(),
It.IsAny<Exception>(),
It.IsAny<Func<object, Exception, string>>())
);
}
}

It.IsAny<Func<object, Exception, string>>())更改为(Func<object, Exception, string>) It.IsAny<object>()似乎可以解决问题。 如果您使用的是最小起订量 4.13+,也可以object替换为IsAnyType

在内部,Logger 类使用FormattedLogValues作为状态参数(在我的示例中为object(。结构的变化似乎与它有关。究竟是什么原因我不确定。但是Moq GitHub存储库上似乎存在一个问题,描述了更多细节。似乎还没有具体的解释为什么它曾经有效,但更多信息可能很快就会发布在那里。

https://github.com/moq/moq4/issues/918

我在Github中发现了同样的问题。

我为解决方案制作了一个扩展方法:

public static void VerifyLog<T>(this Mock<ILogger<T>> mockLogger, Func<Times> times)
{
mockLogger.Verify(x => x.Log(
It.IsAny<LogLevel>(),
It.IsAny<EventId>(),
It.Is<It.IsAnyType>((v, t) => true),
It.IsAny<Exception>(),
It.Is<Func<It.IsAnyType, Exception, string>>((v, t) => true)), times);
}

最新更新