简体   繁体   中英

Unit Testing: How to return value asynchronously from mocked interface

I'm trying to unit test a method and assert that the result is of a specific type when calling a mocked 'request provider' which handles HttpClient logic, though I have setup the mocked interface it always returns null.

Previously when using HttpClient I've mocked the HttpMessageHandler and handled the business logic in the method at the other side, however the third party API we are using requires multiple calls to their rest api using GET requests, so I wanted a solution that kept the solution more 'DRY'

The following is the setup I am currently trying to use

_requestProvider.Setup(
    svc => svc.GetAsync<PlayerBalance>(It.IsAny<string>(), It.IsAny<string>()))
    .Returns(() => Task.FromResult(new PlayerBalance
    {
        Balance = 0
    }));

_playerService = new PlayerService(_playerRepository.Object, 
            _secretsService.Object,
            _awsConfig,
            _requestProvider.Object);

My act/assertion

var result = await _playerService.GetPlayerBalanceAsync(request);

result.Should().BeOfType<PlayerBalance>();

The method under test

public async Task<PlayerBalance> GetPlayerBalanceAsync(PlayerBalanceRequest playerBalanceRequest)
{
    if (string.IsNullOrEmpty(playerBalanceRequest.Login)) throw new Exception("Login is a required parameter.");


    string url = $@"myrestendpoint";

    var result = await _requestProvider.GetAsync<List<PlayerBalance>>(url);

    return result.FirstOrDefault();
}

And where it's failing invocation on the mock

public async Task<TResult> GetAsync<TResult>(string uri, string token = "")
{
    HttpClient httpClient = CreateHttpClient(token);
    HttpResponseMessage response = await httpClient.GetAsync(uri);

    await HandleResponse(response);
    string serialized = await response.Content.ReadAsStringAsync();

    TResult result = await Task.Run(() =>
            JsonConvert.DeserializeObject<TResult>(serialized, _serializerSettings));

        return result;
}

When running in 'Strict' it is telling me that it expected invocation but no setup was found. I'm not really sure what else needs setting up here.

the result returned from the last slice of code is always null, but I want it to be PlayerBalance { Balance = 0 }

Any help would be appreciated.

Just to clarify I have also tried my setup in the following ways

.Returns(Task.FromResult(new PlayerBalance
{
    Balance = 0
}));

.ReturnsAsync(new PlayerBalance {
    Balance = 0
});

You are mocking:

_requestProvider.GetAsync<PlayerBalance>(url)

When you should be mocking:

_requestProvider.GetAsync<List<PlayerBalance>>(url)

Setup the mock to expect the desired behavior:

_requestProvider.Setup(
        svc => svc.GetAsync<List<PlayerBalance>>(It.IsAny<string>(), It.IsAny<string>())
    )
    .ReturnsAsync(() => new List<PlayerBalance>() { new PlayerBalance
    {
        Balance = 0
    }});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM