[C#] Using Moq to mock an asynchronous method for a unit test


How do I set up a verifiable expectation on a mocked async method?

For async methods you need to return a completed Task from the setup before using a callback

have a look here:

Using Moq to mock an asynchronous method for a unit test

You're creating a task but never starting it, so it's never completing. However, don't just start the task - instead, change to using Task.FromResult<TResult> which will give you a task which has already completed:

this works

const string KEY = "some_key";
var db = new Mock<IDatabase>();
db.Setup(d => d.HashSetAsync(KEY, It.IsAny<HashEntry[]>(), It.IsAny<CommandFlags>()))
    .Callback<RedisKey, HashEntry[], CommandFlags>((key, hash, flags) => {
        hash.ShouldContain(entry => entry.Name == "customerid");
        hash.ShouldContain(entry => entry.Name == "quotenumber");

I am testing a method for a service that makes a Web API call. Using a normal HttpClient works fine for unit tests if I also run the web service (located in another project in the solution) locally.

However when I check in my changes the build server won't have access to the web service so the tests will fail.

I've devised a way around this for my unit tests by creating an IHttpClient interface and implementing a version that I use in my application. For unit tests, I make a mocked version complete with a mocked asynchronous post method. Here's where I have run into problems. I want to return an OK HttpStatusResult for this particular test. For another similar test I will be returning a bad result.

The test will run but will never complete. It hangs at the await. I am new to asynchronous programming, delegates, and Moq itself and I've been searching SO and google for a while learning new things but I still can't seem to get past this problem.

Here is the method I am trying to test:

public async Task<bool> QueueNotificationAsync(IHttpClient client, Email email)
    // do stuff
        // The test hangs here, never returning
        HttpResponseMessage response = await client.PostAsync(uri, content);

        // more logic here
    // more stuff

Here's my unit test method:

public async Task QueueNotificationAsync_Completes_With_ValidEmail()
    Email email = new Email()
        FromAddress = "bob@example.com",
        ToAddress = "bill@example.com",
        CCAddress = "brian@example.com",
        BCCAddress = "ben@example.com",
        Subject = "Hello",
        Body = "Hello World."
    var mockClient = new Mock<IHttpClient>();
    mockClient.Setup(c => c.PostAsync(
        )).Returns(() => new Task<HttpResponseMessage>(() => new HttpResponseMessage(System.Net.HttpStatusCode.OK)));

    bool result = await _notificationRequestService.QueueNotificationAsync(mockClient.Object, email);

    Assert.IsTrue(result, "Queue failed.");

What am I doing wrong?

Thank you for your help.