c# - 尝试使用辅助方法简化起订量设置语法

标签 c# unit-testing moq linq-expressions mediatr

我们的单元测试中有很多重复的设置,因为我们使用的是 MediatR 库。我们经常看到这样的行:

mockMediator.Setup(m => m.Send(It.IsAny<Command>(), It.IsAny<CancellationToken>())
    .ReturnsAsync("ok");

我想制作一个扩展方法,简化语法以更加强调Command,并且如果我们愿意,仍然可以让我们有条件,例如:

mockMediator.SetupSend(It.IsAny<Command>())
    .ReturnsAsync("ok");
// or
mockMediator.SetupSend(It.Is<Command>(c => c.IsSomething))
    .ReturnsAsync("ok");

此代码可以构建,但不起作用(模拟始终返回 null):

public static ISetup<IMediator, Task<TResult>> SetupRequest<TResult>(this Mock<IMediator> mockMediator, IRequest<TResult> request) {
    return mockMediator.Setup(m => m.Send(request, It.IsAny<CancellationToken>()));
}

从根本上来说:如何将参数传递到稍后进入表达式主体的方法中?是否有受支持的方法来为常用设置制作像这样的 Moq“助手”功能?

最佳答案

如果您只是通过委托(delegate)推迟参数的评估,您现有的扩展方法将起作用:

public static ISetup<IMediator, Task<TResult>> SetupRequest<TResult>(this Mock<IMediator> mockMediator, Func<IRequest<TResult>> request) {
    return mockMediator.Setup(m => m.Send(request.Invoke(), It.IsAny<CancellationToken>()));
}

用作

mockMediator.SetupSend(() => It.IsAny<Command>())
    .ReturnsAsync("ok");
// or
mockMediator.SetupSend(() => It.Is<Command>(c => c.IsSomething))
    .ReturnsAsync("ok");

从根本上来说,它的行为应该与 Jason 在最常见用例中建议的答案相同。不过,这并没有真正记录 Moq 的行为,因此将 It.Is 与表达式树结合使用会更安全。

好的,但是为什么呢?

推迟此处参数的求值可确保在求值 It.IsAny 方法调用之前创建“匹配器上下文”。这可确保 Moq 在遇到 IsAnyIs 表达式时能够注意到正在计算哪个参数。

It.Is 表达式自然地强制执行此操作,因为它采用表达式树,而永远不会急切地求值。

另一种选择是手动构建表达式树,但是围绕它构建一个漂亮的 API 表面区域可能仍然需要对参数进行某种延迟评估,因此它可能不会比现有的获得太多 yield 答案。

关于c# - 尝试使用辅助方法简化起订量设置语法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63475079/

相关文章:

Python:单元测试可以显示预期值和实际值吗?

c#-4.0 - Nuget Moq 4.0.10827 和 InternalsVisibleTo(再次)

c# - 模拟 protected 方法

c# - 我如何最小起订量 System.IO.FileInfo 类...或任何其他没有接口(interface)的类?

c# - 自引用构造函数。这个图案有味道吗?

c# - 使用 DI 在每个 mvc 请求上加载存储库实例

c# - 查找接口(interface)实例背后的具体类型

c# - 如何在Windows Phone中使用只读数据库?

java - 直接对条纹验证注释进行单元测试

java - SpringJunit4ClassRunner——我可以改变注入(inject)资源的生命周期吗?