3

I am trying to test for the results of certain exceptions when Nest has a value in IGetResponse.OriginalException property.

I first set up the response:

var response = A.Fake<Nest.IGetResponse<Dictionary<string, object>>>();
A.CallTo(() => response.OriginalException).Returns(new Exception("Status code 404"));

Then the fake elastic client:

var client = A.Fake<Nest.IElasticClient>();
A.CallTo(client)
    .WithReturnType<Nest.IGetResponse<Dictionary<string, object>>>()
    .Returns(response);

The client gets injected into the class I am testing.

However, when stepping through the code, when the client is called it returns a faked response, but the OriginalException getter has no value. Its not null, but none of the properties has any value. I was expecting the OriginalException.Message to equal Status code 404.

I also tried setting the response object to:

var response = A.Fake<Nest.IGetResponse<Dictionary<string, object>>>();
A.CallTo(() => response.OriginalException.Message).Returns("Status code 404");

... with equally poor results.

How can I set the IGetResponse so I can evaluate OriginalException.Message in the class being tested?

More code was requested. I can show the entire test, and I will show the method being tested. Here is my entire test:

    [TestMethod]
    [ExpectedException(typeof(NotFoundException))]
    public void Get_ClientReturns404_ThrowsNotFoundException()
    {
        // setup
        var request = new DataGetRequest
        {
            CollectionName = string.Empty,
            DocumentType = string.Empty,
            DataAccessType = string.Empty
        };

        var response = A.Fake<Nest.IGetResponse<Dictionary<string, object>>>();
        A.CallTo(() => response.OriginalException.Message).Returns("Status code 404");

        var client = A.Fake<Nest.IElasticClient>();
        A.CallTo(client)
            .WithReturnType<Nest.IGetResponse<Dictionary<string, object>>>()
            .Returns(response);

        var elasticSearch = new ElasticSearch(null, client);

        // test
        var result = elasticSearch.Get(request);

        // assert
        Assert.Fail("Should have hit an exception.");
    }
}

And here is the method being tested:

    public async Task<Dictionary<string, object>> Get(DataGetRequest getRequest)
    {
        GetRequest request = new GetRequest(getRequest.CollectionName, getRequest.DocumentType, getRequest.Id);
        var response = await Client.GetAsync<Dictionary<string, object>>(request);

        if (response.OriginalException != null)
        {
            var message = response.OriginalException.Message;
            if (message.Contains("Status code 404"))
                throw new NotFoundException(String.Format("Not Found for id {0}", getRequest.Id));
            else
                throw new Exception(message);
        }                

        return response.Source;
    }

The error handling in the IF block is not very robust. Once the unit test works then the code will likely receive more love.

Sailing Judo
  • 11,083
  • 20
  • 66
  • 97
  • Nothing's popping out at me. Are you able to paste more code? Ideally a runnable test, but at least how you inject the client into the class you're testing, how you call that class, and what the called method does? – Blair Conrad Nov 09 '18 at 20:25
  • @BlairConrad Done. Not sure how much help it will be, but you never know. – Sailing Judo Nov 09 '18 at 20:33

1 Answers1

2

The return type of the mocked client is wrong as the IElasticClient.GetAsync<> returns a Task<IGetResponse<T>>.

Task<IGetResponse<T>> GetAsync<T>(IGetRequest request, CancellationToken cancellationToken = default(CancellationToken)) where T : class;

Source

So the setup needs to return a Task derived result to allow the async code

var response = await Client.GetAsync<Dictionary<string, object>>(request);

to flow as expected.

For example

[TestMethod]
[ExpectedException(typeof(NotFoundException))]
public async Task Get_ClientReturns404_ThrowsNotFoundException() {

    //Arrange
    var originalException = new Exception("Status code 404");

    var response = A.Fake<Nest.IGetResponse<Dictionary<string, object>>>();
    A.CallTo(() => response.OriginalException).Returns(originalException);

    var client = A.Fake<Nest.IElasticClient>();
    A.CallTo(() => 
        client.GetAsync<Dictionary<string, object>>(A<IGetRequest>._, A<CancellationToken>._)
    ).Returns(Task.FromResult(response));

    var request = new DataGetRequest {
        CollectionName = string.Empty,
        DocumentType = string.Empty,
        DataAccessType = string.Empty
    };

    var elasticSearch = new ElasticSearch(null, client);

    // Act
    var result = await elasticSearch.Get(request);

    // Assert
    Assert.Fail("Should have hit an exception.");
}
Nkosi
  • 235,767
  • 35
  • 427
  • 472
  • 1
    Nice. And a bonus +1 for faking `GetAsync` directly rather than using the powerful, but potentially error-prone, `WithReturnType` syntax. – Blair Conrad Nov 10 '18 at 17:31