单元测试时如何模拟 ElasticsearchOperations (spring-data-elasticsearch v.4.0.3)

How to mock ElasticsearchOperations (spring-data-elasticsearch v.4.0.3) when unit testing

我正在开发一个项目,该项目使用 Spring 2.3.3、spring-data-elastic-4.0.3、ElasticSearch 7.9.0 和 mockito-core 3.3.3

我在编写单元测试时尝试模拟 ElasticsearchOperations,这是我想测试的服务(使用 ElasticsearchOperations 的地方):

@Service
public class SearchByLabelServiceImpl implements SearchByLabelService {
     private ElasticsearchOperations elasticsearchTemplate;
    
        public SearchByLabelServiceImpl(ElasticsearchOperations elasticsearchTemplate) {
            this.elasticsearchTemplate = elasticsearchTemplate;
        }
    
    public SearchPage<TagResponse> searchByLabel(String query, List<String> labelsToExclude, boolean shouldIncludeDescription, Pageable pageable) {

    ....
    enter code here
    var result = elasticsearchTemplate.search(nativeSearchQuery, TagResponse.class, IndexCoordinates.of(tagIndexName));


}

这是测试 class:

@RunWith(SpringRunner.class)
@SpringBootTest
@ActiveProfiles(profiles = "test")
public class SearchByLabelServiceImplTest {


private ElasticsearchOperations elasticsearchTemplate = mock(ElasticsearchOperations.class);

    private SearchByLabelService searchByLabelService = new SearchByLabelServiceImpl(elasticsearchTemplate);

    @Test
    @Ignore
    public void shouldReturnTheTagsBasedOnSearchRequestIncludingDescription() {

   ...//Arrange

when(elasticsearchTemplate.search(queryArgumentCaptor.capture(), eq(TagResponse.class), IndexCoordinates.of(tagIndexName))).thenReturn(searchHitsResponse);

        var searchResponse = searchByLabelService.searchByLabel(testSearchQuery, testLabelsToExcludeList, true, PageRequest.of(1, 1));

....

//Assertions 

}
   

我得到的错误是这个:

org.mockito.exceptions.base.MockitoException: 
Mockito cannot mock this class: interface org.springframework.data.elasticsearch.core.ElasticsearchOperations.

Mockito can only mock non-private & non-final classes.
If you're not sure why you're getting this error, please report to the mailing list.


Java               : 11
JVM vendor name    : Oracle Corporation
JVM vendor version : 11.0.5+10-LTS
JVM name           : Java HotSpot(TM) 64-Bit Server VM
JVM version        : 11.0.5+10-LTS
JVM info           : mixed mode
OS name            : Mac OS X
OS version         : 10.15.7


Underlying exception : java.lang.TypeNotPresentException: Type org.elasticsearch.cluster.metadata.AliasMetaData not present

    at com.optum.genesis.tag.service.SearchByLabelServiceImplTest.<init>(SearchByLabelServiceImplTest.java:41)
    at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:490)
    at org.junit.runners.BlockJUnit4ClassRunner.createTest(BlockJUnit4ClassRunner.java:250)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:226)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runReflectiveCall(SpringJUnit4ClassRunner.java:289)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:291)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:246)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:97)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:331)
    at org.junit.runners.ParentRunner.schedule(ParentRunner.java:79)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
    at org.junit.runners.ParentRunner.access0(ParentRunner.java:66)
    at org.junit.runners.ParentRunner.evaluate(ParentRunner.java:293)
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
    at org.junit.runners.ParentRunner.evaluate(ParentRunner.java:306)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:190)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
    at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
Caused by: java.lang.TypeNotPresentException: Type org.elasticsearch.cluster.metadata.AliasMetaData not present   

非常感谢。

您正在使用 Spring Data Elasticsearch 4.0.3,它是使用 Elasticsearch 库 7.6.2 构建的,但在运行时您提供的是 Elasticsearch 7.9.0。

Elasticsearch 在 7.6 和 7.9 之间的代码中有一点突破性的变化: class org.elasticsearch.cluster.metadata.AliasMetaData 已重命名为 org.elasticsearch.cluster.metadata.AliasMetadata - 请注意 Dd 的更改 元数据.

那你能做什么?为什么需要在 7.9 中使用 Elasticsearch 库?如果您的集群在 7.9 上是 运行,您可能仍然可以使用 7.6 的客户端库访问它。 或者您更新您的应用程序以使用昨天发布的 Spring Data Elasticsearch 4.1。