Spring 如果 @ComponentScan 来自接口,则无法在测试中加载上下文 class
Spring context failed to load in test class if @ComponentScan is from an Interface
我在 spring 测试中有这种行为,但我没有看到 运行 应用程序。
即使注释 @SpringBootTest(classes = {OpenElevationClient.class})
.
中提到了 OpenElevationClient
接口,我的测试 class 仍无法加载 OpenElevationClientImpl
bean
这个 post 的目的是如果我在 @SpringBootTest
注释中引用 class 和 @ComponentScan
注释来自 OpenElevationClient
接口的同一个包。
测试class
@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);
}
}
}
以下所有class来自同一个包。
OpenElevationClient 接口:bean 未找到 如果此 class 在 @SpringbootTest
@ComponentScan
public interface OpenElevationClient {
LocationElevationResultsDTO getElevation(String locations);
}
OpenElevationConfig class:bean 是 found 如果这个 class 在 @SpringbootTest
@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
仅用作组件 class 用于在测试中加载 ApplicationContext class.我错过了什么可以向我解释这种奇怪的行为吗?
编辑 16/12/2021 - repo 以重现 https://github.com/charlycou/Whosebug-70198445。
- 在测试(AppTest)中将OpenElevationConfig.class替换为OpenElevationClient.class,测试将失败。
- 删除 OpenElevationConfig.class 和 运行 Main.class 并且应用程序 运行 没问题
原题:
在 Ref-doc 中,我只在 @Configuration
类 上看到 @ComponentScan
。
...
但是我可以从您的 (git) 回购协议中得到的是:
Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 2.262 s - in fr.Whosebug.example.app.AppTest
Results:
Tests run: 2, Failures: 0, Errors: 0, Skipped: 0
通过此测试:
package fr.Whosebug.example.app;
import fr.Whosebug.example.api.openelevation.OpenElevationClient;
import fr.Whosebug.example.api.openelevation.OpenElevationConfig;
import fr.Whosebug.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);
}
}
Here 是怎样的(见代码和 git 评论)。
我在 spring 测试中有这种行为,但我没有看到 运行 应用程序。
即使注释 @SpringBootTest(classes = {OpenElevationClient.class})
.
OpenElevationClient
接口,我的测试 class 仍无法加载 OpenElevationClientImpl
bean
这个 post 的目的是如果我在 @SpringBootTest
注释中引用 class 和 @ComponentScan
注释来自 OpenElevationClient
接口的同一个包。
测试class
@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);
}
}
}
以下所有class来自同一个包。
OpenElevationClient 接口:bean 未找到 如果此 class 在 @SpringbootTest
@ComponentScan
public interface OpenElevationClient {
LocationElevationResultsDTO getElevation(String locations);
}
OpenElevationConfig class:bean 是 found 如果这个 class 在 @SpringbootTest
@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
仅用作组件 class 用于在测试中加载 ApplicationContext class.我错过了什么可以向我解释这种奇怪的行为吗?
编辑 16/12/2021 - repo 以重现 https://github.com/charlycou/Whosebug-70198445。
- 在测试(AppTest)中将OpenElevationConfig.class替换为OpenElevationClient.class,测试将失败。
- 删除 OpenElevationConfig.class 和 运行 Main.class 并且应用程序 运行 没问题
原题:
在 Ref-doc 中,我只在 @Configuration
类 上看到 @ComponentScan
。
...
但是我可以从您的 (git) 回购协议中得到的是:
Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 2.262 s - in fr.Whosebug.example.app.AppTest
Results:
Tests run: 2, Failures: 0, Errors: 0, Skipped: 0
通过此测试:
package fr.Whosebug.example.app;
import fr.Whosebug.example.api.openelevation.OpenElevationClient;
import fr.Whosebug.example.api.openelevation.OpenElevationConfig;
import fr.Whosebug.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);
}
}
Here 是怎样的(见代码和 git 评论)。