Closed
Description
Hi,
I'm trying to unit test some code using RestHighLevelClient.
I have
private synchronized void createIndex(String indexName) throws IOException {
if (!client.exists(new GetRequest(indexName), RequestOptions.DEFAULT)) {
CreateIndexRequest request = new CreateIndexRequest(indexName);
request.mapping(indexType, ElasticSearchConstants.MAPPING_SOURCE);
request.alias(new Alias(alias));
request.settings(ElasticSearchConstants.MAPPING_SETTINGS, XContentType.JSON);
client.indices().create(request, RequestOptions.DEFAULT);
}
}
Now i want to verify that client.indices().create was called.
RestHighLevelClient is not final and I was able to mock it.
Mock for RestHighLevelClient.indices() returns null by default.
So of course we want to mock that
when(elasticSearchClient.indices()).thenReturn(mock(IndicesClient.class));
BAM problem. IndicesClient is final class. I can't mock it.
So I can't test if create gets called and with which parameters.
IndicesClient should not be final class or indices() should return an interface and your final class implementation is hidden away.
This is pretty much basic stuff for public APIs guys.
Metadata
Metadata
Assignees
Type
Projects
Milestone
Relationships
Development
No branches or pull requests
Activity
elasticmachine commentedon Mar 27, 2019
Pinging @elastic/es-core-features
jloisel commentedon Jun 10, 2019
Same boat here. Makes it impossible to properly unit test the code => I have to wrap each client to hide it behind an interface which is then mockable. Questionable design here.
jloisel commentedon Jun 12, 2019
I ended up wrapping the client like this:
Then, providing a Spring configuration which instantiates the wrapper:
And the wrapper itself:
This way, I can fully mock every single function injected in the
ElasticsearchClient
. TheRestHighLevelClient
can be easily provided by instantiating it in JUnit.dadoonet commentedon Jun 12, 2019
Thanks @jloisel for sharing your solution.
jloisel commentedon Jun 12, 2019
Sure no problem. Of course, it would be much nicer if the client would have exposed only interfaces. Even other classes like
SearchRequest
are causing mocking issue because its class isfinal
. In that case, i'm instantiating the real object.lxghtless commentedon Sep 5, 2019
FWIW - I was able to use Mockito 2's mock-maker-inline to mock all the things. Here's a snippet of the body of a test that mocks every part used while scrolling.
hub-cap commentedon Sep 9, 2019
Just an fyi, I do not think we will be doing this for now, see #31065 (comment) for more information.
SaurabhRaoot commentedon Feb 11, 2021
This article helped to resolve the issue https://www.baeldung.com/mockito-final
daidorian09 commentedon Oct 14, 2021
We implemented this workaround in order to mock final class using Powermock as testing HighLevelRestClient
mshean commentedon Dec 4, 2021
This is the most unfriendly developer library I've ever experienced in my career. WHY IS EVERYTHING FINAL????
jloisel commentedon Dec 7, 2021
That okay to have most classes and fields as
final
. Immutability is a good thing. The lack of interfaces to hive actual implementation is the real problem.I refuse to use libraries such as
PowerMock
as it usually leads to a horrible, unmaintainable mess. It's a confession of failure when you have to resort toPowerMock
.btljames commentedon Jul 3, 2023
This is even more of an issue in JDK 17 as PowerMock is no longer available. Can we please have any sort of traction on getting this resolved?
dakrone commentedon Mar 8, 2024
Closing this as we've removed the high level rest client in favor of the Java client.