[问题类似于:What is the difference between passing It.IsAny<int>() and the value of It.IsAny<int>() to a method setup - 需要进一步澄清]
(以下更多定义)
我处于我需要在工厂设置模拟的情况。根据值,我想在中选择使用它或It.IsAny<TTypeOfValue>()
。
这是我(天真)想要做的事情:
moq.Setup(() => mockWebService.WebServiceMethod(
webServiceMethodObject.Some ?? It.IsAny<string>(), // that fails
...,
out webServiceMethodObject.That,
...)).Returns(webServiceMethodObject.ReturnEnum);
我有如此大的参数列表(旧的遗留Web服务方法)和很多不同的值组合,我不想手工编写,也不想在任何地方使用It.IsAny<T>()
,因为我想控制返回值取决于参数。
一个可能的替代方案应该是版本,我可以将具体值与具体返回类型匹配,当没有具体值可以匹配时,它会回退到最广泛的版本(所有参数都替换为It.IsAny<T>()
。 (简短示例:在登录测试中,我想测试登录方法的不同输入参数的不同返回值。在所有其他测试中,我只想返回LoginSuccess)。
我怎样才能做到这一点?只有一些表达/反射魔法?
这就是我们典型的遗留Web服务的样子:
ReturnValueEnum WebServiceMethod(string some, int thing, ..., out int that, out byte[] those, ...) { ... }
我们需要这么多的webservice方法调用,而且它们的参数非常繁琐,我们必须将它们封装在对象中。 例如:
public class WebServiceMethodObject
{
public string Some { get; set; }
public int Thing { get; set; }
...
public ReturnValue ReturnEnum { get; set; }
}
策略应该是这样的:我们正在创建此对象的默认版本。在测试中,我们填写了需要匹配的值。我们希望将对象传递给一个待编写的方法,该方法相应地设置模拟:
如果设置了属性:使用该值
其他:使用It.IsAny<T>()
(请参阅上面的设置!)。
答案 0 :(得分:6)
我会想到如果
webServiceMethodObject.Some ?? It.IsAny<string>()
是你想要但不起作用的,简单的替换就是
It.Is<string>(v =>
webServiceMethodObject.Some == null ||
webServiceMethodObject.Some == v)
答案 1 :(得分:2)
如果参数的逻辑非常复杂,您可以安全地对所有参数使用It.IsAny<T>
并定义自定义委托来处理方法调用:
moq
.Setup(() => WebServiceMethod(It.IsAny<string>(), It.IsAny<int>(), ...))
.Returns((some, thing, ...) => {
if (some == webServiceMethodObject.Some || webServiceMethodObject.Some == null) ...
{
return webServiceMethodObject.ReturnEnum;
}
});
如果您查看Returns
重载列表,您会发现有很多选项,“硬编码”.Returns(some value)
只是其中之一。
据我所知,传递给setup的全部内容是表达式树。然后,Moq检查参数的表达式子树。如果它们是基于It
的表达式,则它们用于高级逻辑。如果不是,则评估它们并将值与输入匹配。这可能是您的天真版本不起作用的原因之一。