C# 我能通过吗?是<&燃气轮机;使用另一种方法来设置模拟?

C# 我能通过吗?是<&燃气轮机;使用另一种方法来设置模拟?,c#,moq,C#,Moq,我有这个: myObj.SetupSomething(It.IsAny()) 然后在MyObj类中: public void SetupSomething(string s) { _someMock.Setup(c => c.DoWibble(s)); } 上面的代码不起作用,因为It.IsAny以null的形式出现,因此它将其设置为null,而不是任何字符串。如果我将其替换为: _someMock.Setup(c => c.DoWibble(It.IsAny<str

我有这个:

myObj.SetupSomething(It.IsAny())

然后在MyObj类中:

public void SetupSomething(string s)
{
  _someMock.Setup(c => c.DoWibble(s));
}
上面的代码不起作用,因为
It.IsAny
null
的形式出现,因此它将其设置为
null
,而不是任何字符串。如果我将其替换为:

  _someMock.Setup(c => c.DoWibble(It.IsAny<string>()));
\u someMock.Setup(c=>c.DoWibble(It.IsAny());

那就行了。所以我想知道,我是否可以将
It.IsAny()
的表达式传递给我的方法,以便Moq仍然能够识别我在做什么,或者我是否需要为anyString()
方法额外设置一个
setupsomething()
方法(这有点讨厌)?

正如您所发现的,简短的答案是“不”,不可能只传递一个原始的
It.IsAny()
结果作为设置的参数。但这并不是故事的结尾。Moq如何检测表达式参数并将其转换为匹配器,最终在实际执行期间提供返回值时使用,这有着令人难以置信的细微差别。如果你有时间的话,我绝对建议你看一看源代码。这里有一些很酷的体操表演——不仅仅是表情树分析

在最基本的层面上,使用
It.IsAny()
作为设置之外的参数不起作用的原因与执行顺序有关。考虑:

var x=It.IsAny();
mock.Setup(m=>m.DoWibble(x));
vs

mock.Setup(m=>m.DoWibble(It.IsAny());
它第一个,
It.IsAny()
在任何模拟上下文之外进行计算,在模拟上下文之外,库不能真正返回有意义的值,因此它只返回
default(t)
。然后将该空值绑定为一个变量,该变量在引用的lambda表达式中捕获,
m=>m.DoWibble(x)

整个表达式被传递给
Setup
方法,Moq库将部分计算为参数提供的表达式,包括捕获的值“x”。当前值是
default(string)
,因此它将设置一个匹配器,该匹配器仅在传递空值时工作

在第二个示例中,带引号的表达式现在包括整个
m=>m.DoWibble(It.IsAny())
调用。现在,当Moq部分执行
It.IsAny()
时,它可以与观察者合作执行副作用,通知Moq库为该参数创建“任意”匹配器

但这意味着Moq可以检测到对
It.IsAny
方法的调用,即使它不是作为原始引用lambda的一部分直接调用的。这意味着这同样有效:

Func callIsAny=()=>It.IsAny();
mock.Setup(m=>m.DoWibble(callIsAny.Invoke());
这里的关键是
It.IsAny()
在设置之前的语句中实际上没有被调用,而是在Moq分析mock方法的参数时才被求值。由于它设置了一个检测上下文,以便在调用
it.IsAny
时查看,因此它可以正确地为这种情况创建匹配器

请注意,Moq使用指南中没有记录这一点,因此我不确定这是否是有意的。IsAny的检测上下文可能只用于设置事件处理程序。但是它确实很酷


相反,如果您想要通过某个间接层实际传递参数匹配器,那么最好利用Moq中已有的特性:
it.Is

它将被定义为:

public void SetupSomething(表达式stringMatcher)
{
_Setup(m=>m.DoWibble(It.Is(stringMatcher));
}
用法如下:

myObj.SetupSomething(=>true);//匹配任何东西
myObj.SetupSomething(s=>s==“a”);//仅将呼叫与“a”匹配;
它的可读性不如使用普通的
It.IsAny
调用,但您可以通过将自己的matcher lambda作为属性或方法调用(例如,
Match.Any()
)来减轻这一问题


在这一点上,似乎更像是重新实现了Moq的领域语言。这取决于您是否值得付出努力。

它。*
用于设置表达式中。如果您尝试将它们作为参数传递,它们将默认为默认值。我认为Moq将只有一个
ItIsStringType:string
类,其中包含有关“Any”和其他配置的信息,这是传入的,这意味着只要c继续将原始字符串作为对象传递,String是一个密封的类,这说明了为什么子类化对于一个完全通用的
it.IsAny()
matcher来说不是一个可行的实现。谢谢你这么全面的回答!