英文:
Exclude EurekaClient Bean from Application Context in SpringBootApplicationTest
问题
这是我的测试类
@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
,因为在测试类中不需要它。然而,我需要包含一个配置文件,该文件自动装配了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标记为不需要,但我认为这不太实用,只是为了使测试工作。
解决这个问题的适当方法是什么?
英文:
I'm trying to write a integration test against my Spring Data API with the following test configuration.
eureka:
client:
enabled: false
[..] # No other configuration part that affects discovery/eureka client
This is my test class
@SpringBootTest
@AutoConfigureMockMvc(addFilters = false)
@Transactional
class FooAPITest {
@Test
void contextLoads() {
}
}
However I have a component which injects the EurekaClient to get a service instance from it
@Component
public class ServiceClient {
@Autowired
public ServiceClient(@Qualifier("eurekaClient") EurekaClient eurekaClient) {
URI serviceUri = URI.create(eurekaClient.getNextServerFromEureka("service", false).getHomePageUrl());
}
}
So as of this service my application is not able to load the 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
What I've tried so far
I thought about setting up a custom ContextConfiguration to exclude the ServiceClient
as it is not needed in the test class. However I need to include a Configuration File which autowires the EntityManager but when I use @SpringBootApplication(classes = {Configuration.class})
the EntityManager can not be injected. This Configuration looks like that:
@Configuration
class Configuration {
@Autowired
EntityManager entityManager;
}
This produces the same error but with 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
Current Workaround
Currently I'm avoiding the problem by mocking the ServiceClient
but I want to get rid of that code smell.
@MockBean
ServiceClient serviceClient;
@BeforeEach
void setUp() {
MockitoAnnotations.initMocks(FooAPITest.class);
}
Another workaround would be to mark the Injected Beans as not required but I don't find that practicable only to make the tests work.
What is a proper way to solve this problem?
答案1
得分: 1
你可以尝试在测试中模拟EurekaClient
:
@SpringBootTest
@AutoConfigureMockMvc(addFilters = false)
@Transactional
class FooAPITest {
@MockBean
private EurekaClient eurekaClient;
@Test
void contextLoads() {
}
}
这将在ApplicationContext
中将EurekaClient
创建为一个模拟的bean,以便注入到你的服务中。
如果你有其他初始化Spring ApplicationContext
的测试,你可以在应用程序包中创建一个单独的配置类,以便被扫描(使用@ConditionalOnMissingBean
注解覆盖所有情况):
@Configuration
public class MockEurekaConfiguration {
@Bean
@ConditionalOnMissingBean
public EurekaClient eurekaClient() {
return Mockito.mock(EurekaClient.class);
}
}
英文:
You can try mocking the EurekaClient
in your test:
@SpringBootTest
@AutoConfigureMockMvc(addFilters = false)
@Transactional
class FooAPITest {
@MockBean
private EurekaClient eurekaClient;
@Test
void contextLoads() {
}
}
This will create the EurekaClient
as a mocked bean in the ApplicationContext
to be injected into your service.
If you have other tests that initialize the Spring ApplicationContext
, you can create a separate configuration class within the application package to be scanned (using @ConditionalOnMissingBean
annotation to cover all bases):
@Configuration
public class MockEurekaConfiguration {
@Bean
@ConditionalOnMissingBean
public EurekaClient eurekaClient() {
return Mockito.mock(EurekaClient.class);
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论