你能帮我理解Moq Callback吗?

use*_*969 90 .net moq

使用Moq并查看Callback但我无法找到一个简单的例子来了解如何使用它.

你有一个小的工作片段,清楚地解释了如何以及何时使用它?

Rub*_*ink 76

难以击败https://github.com/Moq/moq4/wiki/Quickstart

如果这还不够清楚,我会称之为doc bug ...

编辑:回应你的澄清......

对于Setup您执行的每个模拟方法,您可以指出以下内容:

  • 对投入的限制
  • / way的值,用于导出返回值(如果有的话)

.Callback机制说"我现在无法描述它,但是当这样的呼叫发生时,请给我回电话,我会做需要做的事情".作为同一个流畅的调用链的一部分,您可以控制结果通过.Returns" 返回(如果有的话)".在QS示例中,一个示例是它们使每次返回的值增加.

一般情况下,您不需要经常使用这样的机制(xUnit测试模式具有针对测试条件逻辑的反模式的术语),如果有任何更简单或内置的方法来确定您需要的内容,它应该是优先使用.

Justin Etheredge的Moq系列中的第3部分包含了它,并且还有另一个回调示例

  • 难以击败[链接]?一点也不.该链接向您显示*如何执行数十种不同的操作,但不会告诉您*为什么*您需要执行其中任何操作.我发现,这是模拟文档中的常见问题.对于我发现的TDD +嘲弄的好的,清晰的解释,我可以指望零手指.大多数人都假设知识水平,如果我有,我就不需要阅读这篇文章了. (13认同)
  • 嗨Ruben我正在学习Moq,如果你愿意,我正在制作大量的例子,以了解如何使用它.我的问题是我不明白何时使用它.一旦我理解问题解决了,我会编写自己的代码.如果你用你自己的话解释它什么时候你会使用回调?谢谢你的时间 (3认同)
  • “我会做需要做的事情,并告诉你返回的结果(如果有)”我认为这是误导,AFAIU `Callback` 与返回值无关(除非你碰巧通过代码链接它) 。基本上,它只是确保在每次调用之前或之后调用回调(取决于您是否分别在“Returns”之前或之后链接它),简单明了。 (2认同)

Jef*_*all 51

下面是使用回调来测试发送到处理插入的数据服务的实体的示例.

var mock = new Mock<IDataService>();
DataEntity insertedEntity = null;

mock.Setup(x => x.Insert(It.IsAny<DataEntity>())).Returns(1) 
           .Callback((DataEntity de) => insertedEntity = de);
Run Code Online (Sandbox Code Playgroud)

替代通用方法语法:

mock.Setup(x => x.Insert(It.IsAny<DataEntity>())).Returns(1) 
           .Callback<DataEntity>(de => insertedEntity = de);
Run Code Online (Sandbox Code Playgroud)

然后你可以测试类似的东西

Assert.AreEqual("test", insertedEntity.Description, "Wrong Description");
Run Code Online (Sandbox Code Playgroud)

  • 对于那个特定的情况(取决于你是否试图表达对状态或行为的测试),在某些情况下,在一个`Mock.Verify`中使用`It.Is <T>`而不是乱扔垃圾可能更干净用temps测试.但+1因为我打赌有很多人会从一个例子中发挥最佳作用. (4认同)

Sha*_*tin 7

Callbackmoq中有两种类型.一个在呼叫返回之前发生; 另一个在调用返回后发生.

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}");
    });
Run Code Online (Sandbox Code Playgroud)

在两个回调中,我们可以:

  1. 检查方法参数
  2. 捕获方法arguemnts
  3. 改变情境状态

  • 实际上,两者都发生在调用返回之前(就调用者而言)。请参阅 /sf/answers/2010896961/。 (3认同)

Oha*_*der 5

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
Run Code Online (Sandbox Code Playgroud)

我最近遇到了一个有趣的用例。假设您希望对模拟进行一些调用,但是它们同时发生。因此,您无法知道呼叫的顺序,但是您想知道发生了预期的呼叫(与顺序无关)。您可以执行以下操作:

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
Run Code Online (Sandbox Code Playgroud)

BTW不要被误导性的“之前Returns”和“之后Returns”区分所迷惑。这仅仅是您的自定义代码将在Returns评估之后还是之前运行的技术区别。在调用者眼中,两者都将在返回值之前运行。确实,如果该方法是void-returning ,则您甚至不能调用Returns它,但是它的作用相同。有关更多信息,请参见/sf/answers/2010896961/