如果@ComponentScan来自接口,则无法在测试类中加载Spring上下文



我在春季测试中有这种行为,但我没有看到它在运行应用程序。

即使@SpringBootTest(classes = {OpenElevationClient.class})注释中提到了OpenElevationClient接口,我的测试类也无法加载OpenElevationClientImplbean。

这篇文章的目的是,如果我在@SpringBootTest注释中引用了来自OpenElevationClient接口的同一个包的具有@ComponentScan注释的类,那么我无法解释OpenElevationClientImplbean是否正确加载。

测试类

@ExtendWith(SpringExtension.class)
@SpringBootTest(classes = {RestClientConfig.class, OpenElevationConfig.class})
public class EnrichmentUtilsTest {
@Autowired
ApplicationContext applicationContext;
@Autowired
OpenElevationClient elevationClient;
@Test
public void printBeans() {
for(String tmp:Arrays.asList(applicationContext.getBeanDefinitionNames())){
System.out.println(tmp);
}
}
}

以下所有类都来自同一个包。

OpenElevationClient接口:如果该类在@SpringbootTest中,则未找到bean

@ComponentScan
public interface OpenElevationClient {
LocationElevationResultsDTO getElevation(String locations);
}

OpenElevationConfig类:如果该类在@SpringbootTest中,则找到bean

@ComponentScan
public class OpenElevationConfig {
}

OpenElevationClientImpl bean

@Service
public class OpenElevationClientImpl implements OpenElevationClient {
private OpenElevationLookupApi openElevationLookupApi;
@Autowired
public OpenElevationClientImpl(OpenElevationLookupApi openElevationLookupApi, @Value("${openelevation.api.url}") String basePath) {
openElevationLookupApi.getApiClient().setBasePath(basePath);
this.openElevationLookupApi = openElevationLookupApi;
}
@Override
public LocationElevationResultsDTO getElevation(String locations) {
return this.openElevationLookupApi.getLookup(locations);
}
}

同样,这种行为仅在运行测试时可见,OpenElevationConfig.class仅用作组件类,用于在测试类中加载ApplicationContext。我错过了什么可以向我解释这种奇怪行为的东西?


编辑16/12/2021-回购以复制https://github.com/charlycou/stackoverflow-70198445.

  1. 在测试(AppTest(中将OpenElevationConfig.class替换为OpenElevation Client.class,测试将失败
  2. 删除OpenElevationConfig.class并运行Main.class,应用程序运行良好

对于原始问题:

在参考文档中,我只在@Configuration类上看到@ComponentScan


但我能从你的(git(回购中得到的是:

Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 2.262 s - in fr.stackoverflow.example.app.AppTest
Results:
Tests run: 2, Failures: 0, Errors: 0, Skipped: 0

这个测试:

package fr.stackoverflow.example.app;
import fr.stackoverflow.example.api.openelevation.OpenElevationClient;
import fr.stackoverflow.example.api.openelevation.OpenElevationConfig;
import fr.stackoverflow.example.api.openelevation.model.LocationElevationResultsDTO;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit.jupiter.SpringExtension;
@ExtendWith(SpringExtension.class)
@SpringBootTest(classes = {
OpenElevationConfig.class // c'est ca!
})
public class AppTest {
@Autowired
OpenElevationClient elevationClient;
@Test
public void testBad() {
assertThrows(org.springframework.web.client.HttpClientErrorException.BadRequest.class, () -> {
this.elevationClient.getElevation("dummy");
});
}
@Test
public void testGood() {
LocationElevationResultsDTO elevation = elevationClient.getElevation("41.161758,-8.583933");
assertNotNull(elevation);
assertNotNull(elevation.getResults());
assertThat(elevation.getResults().isEmpty()).isFalse();
assertNotNull(elevation.getResults().get(0));
assertNotNull(elevation.getResults().get(0).getElevation());
assertThat(elevation.getResults().get(0).getElevation()).isEqualTo(117);
}
}

以下是操作方法(请参阅代码和git注释(。

最新更新