I am attempting to mock a complicated situation for unit testing:
_mockController = new Mock<IController>();
_mockController.Setup(tc => tc.Interrupt(It.IsAny<Func<Task>>()))
    .Callback<Func<Task>>(async f => await f.Invoke());
Where IController has a void method Interrupt(Func<Task>> f), which queues some work to be done.
My objects under test do call Interrupt(), and I can verify the call like so:
_mockController.Verify(tc => tc.Interrupt(It.IsAny<Func<Task>>()), Times.Once);
...but when the argument Func<Task> is invoked in the callback, the await keyword is not respected in the Task: the execution of the test continues before the Task finishes (despite the await in the callback).  One symptom of this is that adding an await Task.Delay(1000) in the Interrupt() Task argument turns a passing test into a failing test.
Is this behavior due to a nuance of how threads or Tasks are handled during test?  Or a limitation of Moq?  My test methods have this signature:
[Test]
public async Task Test_Name()
{
}
                Callback can't return a value, and thus shouldn't be used to execute asynchronous code (or synchronous code that needs to return a value). Callback is a kind of "injection point" that you can hook into to examine the parameters passed to the method, but not modify what it returns.
If you want a lambda mock, you can just use Returns:
_mockController.Setup(tc => tc.Interrupt(It.IsAny<Func<Task>>()))
    .Returns(async f => await f());
(I'm assuming Interrupt returns Task).
the execution of the test continues before the Task finishes (despite the await in the callback).
Yes, since Callback can't return a value, it's always typed as Action/Action<...>, so your async lambda ends up being an async void method, with all the problems that brings (as described in my MSDN article).
Update:
Interrupt() is actually a void method: what it does is queue the function (the argument) until the IController can be bothered to stop what it is doing. Then it invokes the function--which returns a Task--and awaits that Task
You can mock that behavior then, if this would work:
List<Func<Task>> queue = new List<Func<Task>>();
_mockController.Setup(tc => tc.Interrupt(It.IsAny<Func<Task>>()))
    .Callback<Func<Task>>(f => queue.Add(f));
... // Code that calls Interrupt
// Start all queued tasks and wait for them to complete.
await Task.WhenAll(queue.Select(f => f()));
... // Assert / Verify
                        If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With