排除在SpringBootApplicationTest中的EurekaClient Bean从应用程序上下文中。

huangapple go评论70阅读模式
英文:

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);
  }

}

huangapple
  • 本文由 发表于 2020年9月3日 22:23:21
  • 转载请务必保留本文链接:https://go.coder-hub.com/63725658.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定