Can you help me understand Moq Callback?

.NetMoq

.Net Problem Overview


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?

.Net Solutions


Solution 1 - .Net

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.

Solution 2 - .Net

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

Solution 3 - .Net

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.

Solution 4 - .Net

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 arguments
  3. change contextual state

Solution 5 - .Net

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.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionuser9969View Question on Stackoverflow
Solution 1 - .NetRuben BartelinkView Answer on Stackoverflow
Solution 2 - .NetJeff HallView Answer on Stackoverflow
Solution 3 - .NetOhad SchneiderView Answer on Stackoverflow
Solution 4 - .NetShaun LuttinView Answer on Stackoverflow
Solution 5 - .NetFrank BryceView Answer on Stackoverflow