Answers:
很难击败https://github.com/Moq/moq4/wiki/Quickstart
如果还不够清楚,我会称其为文档错误...
编辑:为响应您的澄清...
对于Setup
执行的每个模拟方法,您都需要指出以下内容:
该.Callback
机制说:“我现在无法描述,但是当发生这样的呼叫时,请给我回电,然后我将做需要做的事情”。作为同一条流畅的调用链的一部分,您可以控制结果通过.Returns
“” 返回(如果有的话)。在QS示例中,一个示例是使返回值每次都增加。
通常,您将不需要这种机制(xUnit测试模式具有测试中类似的条件逻辑的反模式术语),并且如果有任何更简单或内置的方式来建立所需的东西,应该优先使用。
Justin Etheredge的Moq系列的4的第3部分对此进行了介绍,这里还有另一个回调示例
一个简单的回调示例可以在使用Moq回调中找到。
Callback
与返回值无关(除非您碰巧通过代码将其链接)。基本上,它仅确保在每次调用之前或之后(取决于是否Returns
分别在其之前或之后将其链接)都以简单和简单的方式调用回调。
这是一个使用回调测试发送到处理插入的数据服务的实体的示例。
var mock = new Mock<IDataService>();
DataEntity insertedEntity = null;
mock.Setup(x => x.Insert(It.IsAny<DataEntity>())).Returns(1)
.Callback((DataEntity de) => insertedEntity = de);
替代的通用方法语法:
mock.Setup(x => x.Insert(It.IsAny<DataEntity>())).Returns(1)
.Callback<DataEntity>(de => insertedEntity = de);
然后您可以测试类似
Assert.AreEqual("test", insertedEntity.Description, "Wrong Description");
It.Is<T>
in Mock.Verify
代替使用临时的测试可能会更干净。但是+1是因为我敢打赌,从一个例子来看,有很多人会做得最好。
Callback
最小起订量有两种类型。一种情况是在呼叫返回之前发生;另一个发生在通话返回后。
var message = "";
mock.Setup(foo => foo.Execute(arg1: "ping", arg2: "pong"))
.Callback((x, y) =>
{
message = "Rally on!";
Console.WriteLine($"args before returns {x} {y}");
})
.Returns(message) // Rally on!
.Callback((x, y) =>
{
message = "Rally over!";
Console.WriteLine("arg after returns {x} {y}");
});
在这两个回调中,我们可以:
Callback
只是在调用模拟方法之一时执行所需的任何自定义代码的一种方法。这是一个简单的例子:
public interface IFoo
{
int Bar(bool b);
}
var mock = new Mock<IFoo>();
mock.Setup(mc => mc.Bar(It.IsAny<bool>()))
.Callback<bool>(b => Console.WriteLine("Bar called with: " + b))
.Returns(42);
var ret = mock.Object.Bar(true);
Console.WriteLine("Result: " + ret);
// output:
// Bar called with: True
// Result: 42
我最近遇到了一个有趣的用例。假设您希望对模拟进行一些调用,但是它们同时发生。因此,您无法知道呼叫的顺序,但是您想知道发生了预期的呼叫(与顺序无关)。您可以执行以下操作:
var cq = new ConcurrentQueue<bool>();
mock.Setup(f => f.Bar(It.IsAny<bool>())).Callback<bool>(cq.Enqueue);
Parallel.Invoke(() => mock.Object.Bar(true), () => mock.Object.Bar(false));
Console.WriteLine("Invocations: " + String.Join(", ", cq));
// output:
// Invocations: True, False
BTW不要被误导性的“之前Returns
”和“之后Returns
”区分所迷惑。这仅仅是您的自定义代码Returns
在评估之后还是之前运行的技术区别。在调用者眼中,两者都将在返回值之前运行。确实,如果该方法是void
-returning ,则您甚至都不能调用Returns
它,但是它的作用相同。有关更多信息,请参见https://stackoverflow.com/a/28727099/67824。