Moq callback for ReturnsAsync
I am currently refactoring an API for asynchronous actions and I need to refactor my tests for async. I have a similar case as in the Moq Documentation :
// returning different values on each invocation
var mock = new Mock<IFoo>();
var calls = 0;
mock.Setup(foo => foo.GetCountThing())
.Returns(() => calls)
.Callback(() => calls++);
// returns 0 on first invocation, 1 on the next, and so on
Console.WriteLine(mock.Object.GetCountThing());
And I need to change it to:
// returning different values on each invocation
var mock = new Mock<IFoo>();
var calls = 0;
mock.Setup(foo => foo.GetCountThingAsync())
.ReturnsAsync(calls)
.Callback(() => calls++);
// returns 0 on first invocation, 1 on the next, and so on
Console.WriteLine(mock.Object.GetCountThingAsync());
But since ReturnAsync()
it doesn't support lambda yet, the callback is called, but apparently in a different context, and hence the variable remains the value for the next call instead of incrementing. Is there a way to solve this problem?
source to share
In the first example, you are passing a lambda to a method Returns
, and that lambda is reevaluated every time the mock method is called. Because of this, you can combine Callback
andReturns
var mock = new Mock<IFoo>();
var calls = 0;
mock.Setup(foo => foo.GetCountThing())
.Returns(() => calls++);
Console.WriteLine(mock.Object.GetCountThing());
In the second example, you are passing the value 0 to the method ReturnsAsync
, so it must return zero every time. Although ReturnsAsync
does not support transmission Func
, you can still use Returns
like this
var mock = new Mock<IFoo>();
var calls = 0;
mock.Setup(foo => foo.GetCountThingAsync())
.Returns(() => Task.FromResult(calls++));
Console.WriteLine(await mock.Object.GetCountThingAsync());
source to share