从 SpringBootApplicationTest 中的应用程序上下文中排除 EurekaClient Bean
Exclude EurekaClient Bean from Application Context in SpringBootApplicationTest
我正在尝试使用以下测试配置针对我的 Spring 数据 API 编写集成测试。
eureka:
client:
enabled: false
[..] # No other configuration part that affects discovery/eureka client
这是我的测试class
@SpringBootTest
@AutoConfigureMockMvc(addFilters = false)
@Transactional
class FooAPITest {
@Test
void contextLoads() {
}
}
但是我有一个组件注入 EurekaClient 以从中获取服务实例
@Component
public class ServiceClient {
@Autowired
public ServiceClient(@Qualifier("eurekaClient") EurekaClient eurekaClient) {
URI serviceUri = URI.create(eurekaClient.getNextServerFromEureka("service", false).getHomePageUrl());
}
}
因此,对于此服务,我的应用程序无法加载 ApplicationContext。
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.netflix.discovery.EurekaClient' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Qualifier(value="eurekaClient")}
at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1695)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1253)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1207)
at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:885)
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:789)
... 81 more
到目前为止我尝试了什么
我考虑过设置自定义 ContextConfiguration 以排除 ServiceClient
,因为测试 class 不需要它。但是,我需要包含一个自动装配 EntityManager 的配置文件,但是当我使用 @SpringBootApplication(classes = {Configuration.class})
时,无法注入 EntityManager。此配置如下所示:
@Configuration
class Configuration {
@Autowired
EntityManager entityManager;
}
这会产生相同的错误,但使用 EntityManager Bean:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'javax.persistence.EntityManager' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1695)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1253)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1207)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:640)
... 81 more
当前解决方法
目前我通过模拟 ServiceClient
来避免这个问题,但我想摆脱那种代码味道。
@MockBean
ServiceClient serviceClient;
@BeforeEach
void setUp() {
MockitoAnnotations.initMocks(FooAPITest.class);
}
另一种解决方法是将注入的 Bean 标记为不需要,但我认为仅使测试工作不可行。
解决这个问题的正确方法是什么?
您可以尝试在测试中模拟 EurekaClient
:
@SpringBootTest
@AutoConfigureMockMvc(addFilters = false)
@Transactional
class FooAPITest {
@MockBean
private EurekaClient eurekaClient;
@Test
void contextLoads() {
}
}
这将创建 EurekaClient
作为 ApplicationContext
中的模拟 bean 以注入到您的服务中。
如果你有其他初始化 Spring ApplicationContext
的测试,你可以在要扫描的应用程序包中创建一个单独的配置 class(使用 @ConditionalOnMissingBean
注解覆盖所有基地):
@Configuration
public class MockEurekaConfiguration {
@Bean
@ConditionalOnMissingBean
public EurekaClient eurekaClient() {
return Mockito.mock(EurekaClient.class);
}
}
我正在尝试使用以下测试配置针对我的 Spring 数据 API 编写集成测试。
eureka:
client:
enabled: false
[..] # No other configuration part that affects discovery/eureka client
这是我的测试class
@SpringBootTest
@AutoConfigureMockMvc(addFilters = false)
@Transactional
class FooAPITest {
@Test
void contextLoads() {
}
}
但是我有一个组件注入 EurekaClient 以从中获取服务实例
@Component
public class ServiceClient {
@Autowired
public ServiceClient(@Qualifier("eurekaClient") EurekaClient eurekaClient) {
URI serviceUri = URI.create(eurekaClient.getNextServerFromEureka("service", false).getHomePageUrl());
}
}
因此,对于此服务,我的应用程序无法加载 ApplicationContext。
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.netflix.discovery.EurekaClient' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Qualifier(value="eurekaClient")}
at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1695)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1253)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1207)
at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:885)
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:789)
... 81 more
到目前为止我尝试了什么
我考虑过设置自定义 ContextConfiguration 以排除 ServiceClient
,因为测试 class 不需要它。但是,我需要包含一个自动装配 EntityManager 的配置文件,但是当我使用 @SpringBootApplication(classes = {Configuration.class})
时,无法注入 EntityManager。此配置如下所示:
@Configuration
class Configuration {
@Autowired
EntityManager entityManager;
}
这会产生相同的错误,但使用 EntityManager Bean:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'javax.persistence.EntityManager' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1695)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1253)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1207)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:640)
... 81 more
当前解决方法
目前我通过模拟 ServiceClient
来避免这个问题,但我想摆脱那种代码味道。
@MockBean
ServiceClient serviceClient;
@BeforeEach
void setUp() {
MockitoAnnotations.initMocks(FooAPITest.class);
}
另一种解决方法是将注入的 Bean 标记为不需要,但我认为仅使测试工作不可行。
解决这个问题的正确方法是什么?
您可以尝试在测试中模拟 EurekaClient
:
@SpringBootTest
@AutoConfigureMockMvc(addFilters = false)
@Transactional
class FooAPITest {
@MockBean
private EurekaClient eurekaClient;
@Test
void contextLoads() {
}
}
这将创建 EurekaClient
作为 ApplicationContext
中的模拟 bean 以注入到您的服务中。
如果你有其他初始化 Spring ApplicationContext
的测试,你可以在要扫描的应用程序包中创建一个单独的配置 class(使用 @ConditionalOnMissingBean
注解覆盖所有基地):
@Configuration
public class MockEurekaConfiguration {
@Bean
@ConditionalOnMissingBean
public EurekaClient eurekaClient() {
return Mockito.mock(EurekaClient.class);
}
}