Hello, I'm relatively new to .NET ecosystem and I'm trying to write some unit tests for the new elasticsearch .NET client (v 8.16.3) and I'm running into some issues.
It seems in the past, (NEST client) you were able to mock the ISearchResponse interface and that would give you an easy mock to handle. However I don't see that interface anymore in the new client.
So after a ton of searching I found TestableResponseFactory which creates a real SearchResponse instead of a mock, and seems to be the new tool meant to accomplish testing. Which seems to work well except I'm still getting NullPointerException when trying to access my searchResponse.Documents in the code I'm testing.
var temp = new SearchResponse<GlobalWorkstationWorkflowInfo>();
_searchResponse = TestableResponseFactory.CreateSuccessfulResponse(temp, 200);
//returns _searchResponse correctly, but throws NPE when trying to access _searchResponse.Documents :(
_elasticSearchClientMock.Setup(x => x.SearchAsync<GlobalWorkstationWorkflowInfo>(It.IsAny<SearchRequestDescriptor<GlobalWorkstationWorkflowInfo>>(), default)).ReturnsAsync(_searchResponse);
I don't see an easy way to setup Documents using the new TestableResponseFactory, so I feel stuck now and I don't know where to go.
Could you please provide any more examples on how to test using the new .NET client? Specifically on how to handle documents?
Just a few words related to this style of testing in general:
IMO you are mocking on the wrong abtraction level. Currently, you are trying to mimic the Elasticsearch client/server behavior - which in the end does not really verify anything meaningful.
Do you have some kind of repository pattern in your application? If yes, then this would be the place where I could imagine using mocks; otherwise, you probably want an integration test instead.
As for the concrete problem:
Documents is not a true property of the response, but is a manually added convenience property (computed property).
You need to stub out the actual response, providing the hits:
var temp = new SearchResponse<GlobalWorkstationWorkflowInfo>()
{
HitsMetadata = new()
{
Hits = [new Hit<GlobalWorkstationWorkflowInfo>() { Source = new GlobalWorkstationWorkflowInfo() }]
}
};
var searchResponse = TestableResponseFactory.CreateSuccessfulResponse(temp, 200);
var docs = searchResponse.Documents;
Right now I'm using the client directly in my service logic, but I see how it could be nice to wrap it with a "repository" class and then just mock that. I think that is the approach I will use since it removes all the elastic logic out of my service.
However, the solution you provided to mock the response worked!
To me it still seems to me that being able to mock SearchResponse would be easier and it seems strange that ISearchResponse was removed.
Apache, Apache Lucene, Apache Hadoop, Hadoop, HDFS and the yellow elephant
logo are trademarks of the
Apache Software Foundation
in the United States and/or other countries.