Can you help me understand Moq Callback?

自古美人都是妖i 提交于 2019-11-29 04:22:04

问题


Using Moq and looked at Callback but I have not been able to find a simple example to understand how to use it.

Do you have a small working snippet which clearly explain how and when to use it?


回答1:


Hard to beat https://github.com/Moq/moq4/wiki/Quickstart

If that's not clear enough, I'd call that a doc bug...

EDIT: In response to your clarification...

For each mocked method Setup you perform, you get to indicate things like:

  • constraints on inputs
  • the value for / way in which the return value (if there is one) is to be derived

The .Callback mechanism says "I can't describe it right now, but when a call shaped like this happens, call me back and I'll do what needs to be done". As part of the same fluent call chain, you get to control the result to return (if any) via .Returns". In the QS examples, an example is that they make the value being returned increase each time.

In general, you won't need a mechanism like this very often (xUnit Test Patterns have terms for antipatterns of the ilk Conditional Logic In Tests), and if there's any simpler or built-in way to establish what you need, it should be used in preference.

Part 3 of 4 in Justin Etheredge's Moq series covers it, and there's another example of callbacks here

A simple example of a callback can be found at Using Callbacks with Moq post.




回答2:


Here's an example of using a callback to test an entity sent to a Data Service that handles an insert.

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

mock.Setup(x => x.Insert(It.IsAny<DataEntity>())).Returns(1) 
           .Callback((DataEntity de) => insertedEntity = de);

Alternative generic method syntax:

mock.Setup(x => x.Insert(It.IsAny<DataEntity>())).Returns(1) 
           .Callback<DataEntity>(de => insertedEntity = de);

Then you can test something like

Assert.AreEqual("test", insertedEntity.Description, "Wrong Description");



回答3:


There are two types of Callback in moq. One happens before the call returns; the other happens after the call returns.

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}");
    });

In both callbacks, we can:

  1. inspect method arguments
  2. capture method arguemnts
  3. change contextual state



回答4:


Callback is simply a means to execute any custom code you want when a call is made to one of the mock's methods. Here's a simple example:

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

I recently ran into an interesting use case for it. Suppose you expect some calls to your mock, but they happen concurrently. So you have no way of knowing the order in which they'd get called, but you want to know the calls you expected did take place (irrespective of order). You can do something like this:

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 don't get confused by the misleading "before Returns" and "after Returns" distinction. It is merely a technical distinction of whether your custom code will run after Returns has been evaluated or before. In the eyes of the caller, both will run before the value is returned. Indeed, if the method is void-returning you can't even call Returns and yet it works the same. For more information see https://stackoverflow.com/a/28727099/67824.




回答5:


On top of the other good answers here, I've used it to perform logic before throwing an exception. For instance, I needed to store all objects that were passed to a method for later verification, and that method (in some test cases) needed to throw an exception. Calling .Throws(...) on Mock.Setup(...) overrides the Callback() action and never calls it. However, by throwing an exception within the Callback, you can still do all of the good stuff that a callback has to offer, and still throw an exception.



来源:https://stackoverflow.com/questions/2833162/can-you-help-me-understand-moq-callback

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!