我正在为 Spring Boot 应用程序设置一个模板 - 在最新版本上
3.2.4
。我面临的问题是测试用例。
我正在使用
@WebFluxTest
在 控制器 上运行测试用例,但不知何故它并没有跳过与数据库相关的自定义 Spring beans :/
这就是应用程序的配置方式(为简洁起见,跳过导入和构造函数):
@SpringBootApplication(scanBasePackages = { "tld.domain.controller", "tld.domain.service" })
public class Application {
public static void main(final String... args) {
SpringApplication.run(Application.class, args);
}
@EnableTransactionManagement
@Configuration(proxyBeanMethods = false)
@EnableJdbiRepositories(basePackages = "tld.domain.repository")
public static class PersistenceConfig {
@Bean
public Jdbi jdbi(final DataSource dataSource) {
return Jdbi.create(new SpringConnectionFactory(dataSource))
.installPlugin(new SqlObjectPlugin());
}
}
}
控制器、服务和存储库类非常标准:
@RestController
public class TypeResource {
final TypeService service;
@GetMapping(path = "/{id}", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Type> getByID(@PathVariable("id") final String id) {
return ResponseEntity.of(service.getByID(id));
}
}
@Service
public class TypeService {
final TypeRepository repository;
public Optional<Type> getByID(final String id) {
return repository.getByID(id);
}
}
最后,示例控制器的测试用例如下所示:
@ActiveProfiles("test")
@WebFluxTest(controllers = TypeResource.class)
final class TypeResourceTest {
@Autowired
private WebTestClient webClient;
@MockBean
private TypeService service;
...
}
尽管使用了
@WebFluxTest
,测试用例并没有跳过与数据库相关的自定义 Spring bean 配置,从而导致测试环境中出现意外行为。
这些是堆栈跟踪的相关部分:
TypeResourceTest > getByID() FAILED
java.lang.IllegalStateException: Failed to load ApplicationContext for [ReactiveWebMergedContextConfiguration@4afd65fd testClass = tld.domain.resource.TypeResourceTest, locations = [], classes = [tld.domain.Application], contextInitializerClasses = [], activeProfiles = ["test"], propertySourceDescriptors = [], propertySourceProperties = ["org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTestContextBootstrapper=true"], contextCustomizers = [org.springframework.boot.testcontainers.service.connection.ServiceConnectionContextCustomizer@0, org.springframework.boot.test.autoconfigure.OverrideAutoConfigurationContextCustomizerFactory$DisableAutoConfigurationContextCustomizer@30f4b1a6, org.springframework.boot.test.autoconfigure.actuate.observability.ObservabilityContextCustomizerFactory$DisableObservabilityContextCustomizer@1f, org.springframework.boot.test.autoconfigure.filter.TypeExcludeFiltersContextCustomizer@14ff57cc, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@e5029446, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizer@2fb69ff6, [ImportsContextCustomizer@4b5ad306 key = [org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration, org.springframework.boot.autoconfigure.security.reactive.ReactiveUserDetailsServiceAutoConfiguration, org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration, org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration, org.springframework.boot.autoconfigure.web.reactive.error.ErrorWebFluxAutoConfiguration, org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration, org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration, org.springframework.boot.autoconfigure.security.oauth2.resource.reactive.ReactiveOAuth2ResourceServerAutoConfiguration, org.springframework.boot.test.autoconfigure.web.reactive.WebTestClientAutoConfiguration, org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration, org.springframework.boot.autoconfigure.gson.GsonAutoConfiguration, org.springframework.boot.autoconfigure.jsonb.JsonbAutoConfiguration, org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration, org.springframework.boot.autoconfigure.web.reactive.WebFluxAutoConfiguration, org.springframework.boot.autoconfigure.security.oauth2.client.reactive.ReactiveOAuth2ClientAutoConfiguration, org.springframework.boot.autoconfigure.http.codec.CodecsAutoConfiguration, org.springframework.boot.autoconfigure.mustache.MustacheAutoConfiguration]], org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@d4602a, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@15515c51, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@be84b7c9, org.springframework.boot.test.context.SpringBootTestAnnotation@e0ed3db8], contextLoader = org.springframework.boot.test.context.SpringBootContextLoader, parent = null]
at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:180)
...
Caused by:
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'jdbi' defined in tld.domain.Application$PersistenceConfig: Unsatisfied dependency expressed through method 'jdbi' parameter 0: No qualifying bean of type 'javax.sql.DataSource' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
at app//org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:798)
at app//org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:542)
... 85 more
Caused by:
org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'javax.sql.DataSource' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
... 109 more
任何有关如何解决此问题的见解或建议将不胜感激。
将
@ConditionalOnBean(DataSource.class)
放在 PersistenceConfig
上解决了问题,因为它有效地确保仅当数据源可用或在应用程序上下文中配置时才加载 PersistenceConfig
中的 bean。