137

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?

Ohad Schneider
  • 36,600
  • 15
  • 168
  • 198
user9969
  • 15,632
  • 39
  • 107
  • 175

6 Answers6

112

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.

Ruben Bartelink
  • 59,778
  • 26
  • 187
  • 249
  • 4
    Hi Ruben I am learning Moq and if you like I am bulding lots of examples to understand how to do things using it. My problem is I dont understand when to use it .Once I understand that problem solved I will write my own code.If you were to explain it in your own word when would you use callback? thanks appreciate your time – user9969 May 17 '10 at 04:59
  • 39
    Hard to beat [link]? Not at all. That link shows you *how* to do dozens of different things, but doesn't tell you *why* you'd need to do any of them. Which is a common problem in mocking documentation, I've found. I can count on zero fingers the number of good, clear explanations of TDD + mocking that I've found. Most assume a level of knowledge which, if I had it, I wouldn't need to read the article. – Ryan Lundy Apr 25 '11 at 21:25
  • @Kyralessa: I take your point. I personally had quite a bit of book knowledge coming in so found the quickstart stuff absoltely perfect. Unfortunately I'm not aware of a better example that the ones I linked to at the end of the post. Should you find one, post it here and I'll be happy to edit it in (or feel free to DIY) – Ruben Bartelink May 03 '11 at 23:40
  • 2
    "I'll do what needs to be done and tell you the result to return (if any)" I think this is misleading, AFAIU `Callback` has nothing to do with the return value (unless you happen to link it through code). Basically it only makes sure the callback is called before or after each invocation (depending on whether you chained it before or after `Returns` respectively), plain and simple. – Ohad Schneider Aug 10 '17 at 09:58
  • 1
    @OhadSchneider Following my link... you are correct! Wonder (but not really interested enough as have not used Moq for a loooong time) if the Fluent interface has changed (doesnt seem likely, i.e. I made a mistaken assumption and didnt read the thing I linked to as I'd normally work it out from autocompletion myself). Hope the fix addresses your point, let me know if it doesnt – Ruben Bartelink Aug 10 '17 at 10:05
  • Brutal - Github disables Google from searching it, so that documentation doesn't even show up on Google searches. Can you even call it documentation in that case, if nobody can find it? – AffluentOwl Mar 08 '23 at 22:28
73

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");
Jeff Hall
  • 1,694
  • 11
  • 7
  • 5
    Arguably for that particular case (depending on whether you're trying to express tests against state or behavior), it may in some instances be cleaner to use an `It.Is` in a `Mock.Verify` instead of littering the test with temps. But +1 because I bet there are lots of people that will work best from an example. – Ruben Bartelink Oct 03 '12 at 15:12
  • Calling Verify at the end of unit tests an atrocious design decision. Setting the expectation when setting up the mock is infinitely more convenient and less redundant. This is why they invented the `Setup(...).Verifiable()` notation in the first place. – AffluentOwl Mar 08 '23 at 22:22
18

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.

Ohad Schneider
  • 36,600
  • 15
  • 168
  • 198
16

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
Pang
  • 9,564
  • 146
  • 81
  • 122
Shaun Luttin
  • 133,272
  • 81
  • 405
  • 467
  • 3
    Actually, both happen before the call returns (as far as the caller is concerned). See https://stackoverflow.com/a/28727099/67824. – Ohad Schneider Aug 10 '17 at 10:53
2

I add an example:

The method which I need to test is called Add. It stores the result in the database by executing another method and returns void.

public class SystemUnderTest
{
    private readonly Repository _repository;

    public SystemUnderTest(Repository repository)
    {
        _repository = repository;
    }

    public void Add(int a, int b)
    {
        int result = a + b;
        _repository.StoreResult(result);
    }
}


public class Repository
{
    public void StoreResult(int result)
    {
        // stores the result in the database
    }
}

Because of the return type of Add, I can't get the result directly and assert it. I have to get the input of the StoreResult method. For this, I use the callback while mocking the method of the Repository.

using Moq;
using Xunit;

namespace TestLocal.Tests;

public class CallbackTest
{
    private readonly SystemUnderTest _sut;
    private readonly Mock<Repository> _repository;

    public CallbackTest()
    {
        _repository = new Mock<Repository>(MockBehavior.Strict);
        _sut = new SystemUnderTest(_repository.Object);

    }

    [Fact]
    public void AddTest()
    {
        int a = 1;
        int b = 2;

        int result = -1;
        _repository.Setup(x => x.StoreResult(3))
            .Callback<int>(callbackResult => result = callbackResult)
            .Verifiable();

        _sut.Add(a,b);

        Assert.Equal(a+b, result);
    }
}
RuhrpottDev
  • 484
  • 5
  • 10
1

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.

Frank Bryce
  • 8,076
  • 4
  • 38
  • 56