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

}