Search code examples
javaspringspring-bootmockitoresthighlevelclient

NullPointerException Problem when trying to mock Elastic Search's RestHighLevelClient


I'm facing a NullPointerException during unit testing, when trying to test and mock a RestHighLevelClient inside an ElasticClient class:

@Configuration
@NoArgsConstructor
public class ElasticClient{

   @Setter
   private RestHighLevelClient restHighLevelClient;

    @PostConstruct
    public void buildRestHighLevelClient(){

        RestClientBuilder restClientBuilder = RestClient.builder(new HttpHost(
                "127.0.0.1",
                9200, "http")
        );

        restClientBuilder.setRequestConfigCallback(
                requestConfigBuilder ->
                        requestConfigBuilder
                                .setConnectTimeout(500000)
                                .setSocketTimeout(600000)
                                .setConnectionRequestTimeout(0)
        )
                .setHttpClientConfigCallback(
                        httpClientBuilder ->
                                httpClientBuilder
                                        .setMaxConnPerRoute(2048)
                );

        restHighLevelClient = new RestHighLevelClient(restClientBuilder);
    }

   public boolean isReachable(){
     return restHighLevelClient.ping(RequestOptions.DEFAULT);
   }

}

And the test class:

@RunWith(MockitoJUnitRunner.class)
@SpringBootTest
public class ElasticClientTest{

@Mock
private RestHighLevelClient restHighLevelClient;


ElasticClient elasticClient;

@Before
public void init(){

    elasticClient = new ElasticClient();
    elasticClient.setRestHighLevelClient(restHighLevelClient);

}

And the NullPointerException is coming from here:

    @Test
    public void whenElasticIsPingable_thenReturnTrue() throws IOException{

           when(restHighLevelClient.ping(RequestOptions.DEFAULT)).thenReturn(true);
           Assertions.assertThat(elasticClient.isReachable()).isTrue();
    }

Here is the stacktrace:

java.lang.NullPointerException
at org.elasticsearch.client.RestHighLevelClient.internalPerformRequest(RestHighLevelClient.java:1764)
at org.elasticsearch.client.RestHighLevelClient.performRequest(RestHighLevelClient.java:1734)
at org.elasticsearch.client.RestHighLevelClient.ping(RestHighLevelClient.java:694)
at com.example.ElasticClientTest.whenElasticIsPingable_thenReturnTrue(ElasticClientTest.java:44)

Solution

  • The problem is originated from the fact that the ping method in the RestHighLevelClient is final as can't be mocked regularly.

    So, I used the help of this example about PowerMock

    And in the final result:

    @RunWith(PowerMockRunner.class)
    @PrepareForTest(RestHighLevelClient.class)
    public class ElasticClientTest{
    
    ElasticClient elasticClient;
    
    RestHighLevelClient restHighLevelClient;
    
    @Before
    public void init(){
    
        restHighLevelClient = mock(RestHighLevelClient.class);
    
        elasticClient = new ElasticClient();
        elasticClient.setRestHighLevelClient(restHighLevelClient);
    
    }
    
    
    @Test
    public void whenElasticIsPingable_thenReturnTrue() throws IOException{
    
        when(restHighLevelClient.ping(RequestOptions.DEFAULT)).thenReturn(true);
    
        Assertions.assertThat(elasticClient.isReachable()).isTrue();
    }