如何用Mockito模拟Elasticsearch Java API Client的search.hits().hits()响应?
如何Mock Elasticsearch Java API Client的search.hits().hits()方法
要成功模拟search.hits().hits()的返回结果,需要按层级构建或Mock响应对象——因为Elasticsearch Java API Client的响应结构是嵌套的:SearchResponse → SearchHits → List<Hit<Product>>。以下是两种可行方案:
方案一:用官方Builder构建模拟响应(推荐)
这种方式使用API Client自带的Builder创建真实的响应实例,避免Mock不可变类的麻烦:
- 准备模拟数据
// 构造模拟的Product对象 Product mockProduct = new Product(); mockProduct.setName("bicycle"); // 构造Hit对象 Hit<Product> mockHit = Hit.of(h -> h .source(mockProduct) .id("product_1") ); List<Hit<Product>> mockHitList = Collections.singletonList(mockHit);
- 构建嵌套的响应结构
// 构建SearchHits SearchHits<Product> mockSearchHits = SearchHits.of(sh -> sh .hits(mockHitList) .total(t -> t.value(1L)) // 设置总命中数,按需调整 ); // 构建最终的SearchResponse SearchResponse<Product> mockResponse = SearchResponse.of(r -> r .hits(mockSearchHits) );
- Mock客户端的search方法
ElasticsearchClient mockClient = Mockito.mock(ElasticsearchClient.class); // 匹配任意SearchRequest和指定的Product类 when(mockClient.search(any(SearchRequest.class), eq(Product.class))) .thenReturn(mockResponse);
方案二:用Mockito逐层Mock嵌套对象
如果需要Mock每个层级的对象,需注意部分类可能是final类型,需要开启Mockito的inline支持(添加mockito-inline依赖或配置测试参数):
- Mock各层级对象
// Mock最外层的SearchResponse SearchResponse<Product> mockSearchResponse = Mockito.mock(SearchResponse.class); // Mock中间层的SearchHits SearchHits<Product> mockSearchHits = Mockito.mock(SearchHits.class); // 准备模拟的Hit列表(mockHit的创建同方案一) List<Hit<Product>> mockHitList = Collections.singletonList(mockHit);
- 关联各层级的Mock行为
when(mockSearchResponse.hits()).thenReturn(mockSearchHits); when(mockSearchHits.hits()).thenReturn(mockHitList); // Mock客户端返回Mock的SearchResponse when(mockClient.search(any(), eq(Product.class))).thenReturn(mockSearchResponse);
注意事项
- 如果使用方案二遇到
Cannot mock/spy class ...错误,说明该类是final的,需添加mockito-inline依赖(Maven/Gradle)来支持Mock final类。 - 优先选择方案一,因为构建的响应实例更贴近真实场景,减少Mock带来的潜在问题。
内容的提问来源于stack exchange,提问作者Ashish Mishra
相关产品推荐
相关产品推荐

