无法Mock Elasticsearch中Aggregations的get方法,求解决方案
问题背景
测试使用Elasticsearch聚合框架的类时,Mock Aggregations 对象的get方法始终抛出NullPointerException,已添加@RunWith(PowerMockRunner)注解,且相关类已包含在@PrepareForTest中。
被测方法
public void aggregation() { //prepare aggregation query SearchResponse response = client.search(query, RequestOptions.DEFAULT); Aggregations aggregations = response.getAggregations(); // mocked aggregations object gets set Terms terms = aggregations.get("field"); //throws NullPointerException //use terms object }
测试方法
@Test public void testAggregation() { RestHighLevelClient client = PowerMockito.mock(RestHighLevelClient.class); testObject.setClient(client); SearchResponse response = PowerMockito.mock(SearchResponse.class); Aggregations aggregations = PowerMockito.mock(Aggregations.class); Terms terms = PowerMockito.mock(Terms.class); PowerMockito.when(client.search(any(SearchRequest.class), any(RequestOptions.class))).thenReturn(response); PowerMockito.when(response.getAggregations()).thenReturn(aggregations); PowerMockito.when(aggregations.get(anyString())).thenReturn(terms); // aggregations.get("field") throws NullPointerException testObject.aggregation(); }
堆栈跟踪
"org.elasticsearch.search.aggregations.Aggregations.equals(Aggregations.java:106)" "org.mockito.internal.invocation.InvocationMatcher.matches(InvocationMatcher.java:61)" "org.mockito.internal.stubbing.InvocationContainerImpl.findAnswerFor(InvocationContainerImpl.java:79)" "org.mockito.internal.handler.MockHandlerImpl.handle(MockHandlerImpl.java:87)" "org.powermock.api.mockito.internal.invocation.MockitoMethodInvocationControl.performIntercept(MockitoMethodInvocationControl.java:244)" "org.powermock.api.mockito.internal.invocation.MockitoMethodInvocationControl.invoke(MockitoMethodInvocationControl.java:196)" "org.powermock.core.MockGateway.doMethodCall(MockGateway.java:182)" "org.powermock.core.MockGateway.doMethodCall(MockGateway.java:164)" "org.powermock.core.MockGateway.methodCall(MockGateway.java:134)" "org.elasticsearch.search.aggregations.Aggregations.get(Aggregations.java)"
解决建议
从堆栈信息看,问题出在Mockito匹配调用时触发了Aggregations.equals()方法,导致空指针。可以尝试以下几种修改方案:
改用具体参数匹配替代通配符:
把PowerMockito.when(aggregations.get(anyString())).thenReturn(terms);改成针对具体字段名的匹配:PowerMockito.when(aggregations.get("field")).thenReturn(terms);通配符
anyString()会触发Mockito的调用匹配逻辑,而Aggregations的equals方法在Mock对象上执行时易出现异常,使用具体参数可绕过这一步。使用doReturn方式存根:
避免使用when(...).thenReturn()语法,改用doReturn——前者会先执行一次被Mock的方法,后者直接指定返回值,不会触发方法调用:PowerMockito.doReturn(terms).when(aggregations).get("field");检查@PrepareForTest和@PowerMockIgnore配置:
确保@PrepareForTest包含Aggregations类本身或其所在包,同时添加@PowerMockIgnore排除Elasticsearch相关类的加载冲突:@PowerMockIgnore({"org.elasticsearch.*", "org.apache.http.*"})验证版本兼容性:
检查Elasticsearch、PowerMock、Mockito三者的版本是否兼容,部分高版本Elasticsearch需要搭配更新的PowerMock/Mockito版本才能正常Mock相关类。
内容的提问来源于stack exchange,提问作者sudhanva

