【问题标题】:Exclude a particular class from Spring Component scan while writing Spring Integration Test在编写 Spring 集成测试时从 Spring 组件扫描中排除特定类
【发布时间】:2017-07-03 20:51:51
【问题描述】:

我的课是..

位于 src/intregation-test/java

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, classes = StoreOrderFulfillmentApplication.class)
  @ActiveProfiles("Test")
  public class OrderCreationIntregationTest {

@Autowired
private TestRestTemplate restTemplate;

@MockBean
private OrderRepository orderRepository;

@MockBean
private OrderLineItemRepository orderLineItemRepository;

@MockBean
private InternalEventPublisher internalEventPublisher;

@SuppressWarnings("unchecked")
@Before
public void setup() {
    Mockito.when(orderRepository.findByOfsReferenceId("OFS:GMO:Z100002062-99")).thenReturn(null);
    OrderEntity savedOrder = new OrderEntity();
    savedOrder.setOrderId(1023);
    Mockito.when(orderRepository.save(Mockito.any(OrderEntity.class))).thenReturn(savedOrder);
    Iterable<OrderLineItemEntity> orderLineItemList = prepareOrderLineItemEntityIterable();
    Mockito.when(orderLineItemRepository.save(Mockito.any(Iterable.class))).thenReturn(orderLineItemList);
}

@Test
public void test() throws ParseException {
    FulfillmentOrder fulfillmentOrderRequestVO = new FulfillmentOrder();
    fulfillmentOrderRequestVO = buildFulfillmentOrder();
    String myMessage = "Order Created";
    ResponseEntity<ResponseOrderMessage> responseEntity = restTemplate.postForEntity("/fulfillmentprocessor/orders",
            fulfillmentOrderRequestVO, ResponseOrderMessage.class);
    ResponseOrderMessage responseOrderMessage = responseEntity.getBody();
    assertEquals(HttpStatus.CREATED, responseEntity.getStatusCode());
    assertEquals(myMessage, responseOrderMessage.getMessage());
}

位于 src/main/java

@SpringBootApplication
public class StoreOrderFulfillmentApplication {

public static void main(String[] args) {
    SpringApplication.run(StoreOrderFulfillmentApplication.class, args);
}
}

现在的问题是我想排除一个类 从被扫描组件开始。我的这个类包含对 apache Kafka 的依赖。 如果此类在容器启动时加载,它将开始寻找 kafka 运行实例。 所以在运行集成测试时我不会启动我的 Kafka 服务器,所以我想运行 集成测试使 kafka 关闭。

我可以通过在 StoreOrderFulfillmentApplication 类中添加一行代码来实现

@ComponentScan(basePackages = "com.tesco.store.order.fulfillment.processor", excludeFilters = @Filter(type = FilterType.ASSIGNABLE_TYPE, classes = OrderReceiveEventConfiguration.class))

通过添加这行代码 StoreOrderFulfillmentApplication 类,它将 OrderReceiveEventConfiguration 类排除在组件扫描之外。

现在的问题是我不认为在主代码中添加任何测试配置更改。 所以我正在努力从 src/intregation-test/java 源文件夹中进行相同的排除,这是我可以在容器启动代码期间排除这个特定类的某种方式。

但它不应该影响我的主类代码意味着 src/main/java

中的代码

感谢任何帮助..

【问题讨论】:

  • 您想在 Kafka 关闭/未运行时测试应用程序的行为,还是只想在测试时忽略 Kafka 部分?
  • 是的@Bond-JavaBond,我想在测试时忽略 kafka 部分......实际上我的要求说,在执行测试套件时,外部依赖项应该像数据库或消息队列一样被模拟......原因在我的测试框中执行此操作 数据库和消息队列服务器不存在,因此我们必须准备我们的测试套件,就像它不应该检查连接一样。

标签: java spring spring-mvc spring-boot spring-test


【解决方案1】:

您可以使用@Conditional,如下所示。

  • 在application.properties 中介绍一个属性,比如kafka.enabled。
  • 用@Conditional(PropertyCondition.class)注释OrderReceiveEventConfiguration
  • 取决于kafka.enabled 值,即。 true(用于正常运行)或false(用于测试)OrderReceiveEventConfiguration 将分别被拾取或忽略,而无需更改代码。

如果需要更多信息,请在 cmets 中告知。


除了主要的@conditional注解外,还有一组类似的注解用于不同的情况。

班级条件

@ConditionalOnClass 和 @ConditionalOnMissingClass 注释允许根据特定类的存在或不存在来包含配置。

例如当 OObjectDatabaseTx.class 添加到依赖项并且没有 OrientWebConfigurer bean 时,我们创建配置器。

@Bean
@ConditionalOnWebApplication
@ConditionalOnClass(OObjectDatabaseTx.class)
@ConditionalOnMissingBean(OrientWebConfigurer.class)
public OrientWebConfigurer orientWebConfigurer() {
    return new OrientWebConfigurer();
}

豆条件

@ConditionalOnBean 和 @ConditionalOnMissingBean 注释允许根据特定 bean 的存在或不存在来包含 bean。您可以使用 value 属性按类型指定 beans,或使用 name 按名称指定 beans。 search 属性允许您限制搜索 bean 时应考虑的 ApplicationContext 层次结构。

检查是否没有定义的bean见上例。

物业条件

@ConditionalOnProperty 注释允许基于 Spring Environment 属性包含配置。使用 prefix 和 name 属性来指定应该检查的属性。默认情况下,任何存在且不等于false 的属性都将被匹配。您还可以使用havingValue 和matchIfMissing 属性创建更高级的检查。

@ConditionalOnProperty(value='somebean.enabled', matchIfMissing = true, havingValue="yes")
@Bean 
public SomeBean someBean(){
}

资源条件

@ConditionalOnResource 注释允许仅在存在特定资源时才包含配置。

@ConditionalOnResource(resources = "classpath:init-db.sql") 

Web应用条件

@ConditionalOnWebApplication 和 @ConditionalOnNotWebApplication 注释允许根据应用程序是否为“Web 应用程序”来包含配置。

@Configuration
@ConditionalOnWebApplication
public class MyWebMvcAutoConfiguration {...}

SpEL 表达式条件

@ConditionalOnExpression 注释允许根据 SpEL 表达式的结果包含配置。

@ConditionalOnExpression("${rest.security.enabled}==false")

【讨论】:

  • @Configuration @EnableBinding(Source.class) public class OrderReceiveEventConfiguration { public OrderReceiveEventConfiguration() { } @Value("${spring.outputChannel.timeout.ms}") private long timeoutMs; public long getTimeoutMs() { return timeoutMs; } public void setTimeoutMs(long timeoutMs) { this.timeoutMs = timeoutMs; } } 这是我的课,你能告诉我如何在这里使用@Conditional*
  • 应该是这样的@Configuration @EnableBinding(Source.class) @Conditional(PropertyCondition.class) public class OrderReceiveEventConfiguration { ... }
【解决方案2】:

你应该能够在你的测试包中创建一个单独的配置类

@SpringBootApplication
@ActiveProfiles("Test")
@ComponentScan(basePackages = "com.tesco.store.order.fulfillment.processor", excludeFilters = @Filter(type = FilterType.ASSIGNABLE_TYPE, classes = OrderReceiveEventConfiguration.class))
public class StoreOrderFulfillmentApplicationTest {

public static void main(String[] args) {
    SpringApplication.run(StoreOrderFulfillmentApplicationTest.class, args);
}
}

然后在你的测试类中

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, classes = StoreOrderFulfillmentApplicationTest.class)
  @ActiveProfiles("Test")
  public class OrderCreationIntregationTest {

@Autowired
private TestRestTemplate restTemplate;

@MockBean
private OrderRepository orderRepository;

@MockBean
private OrderLineItemRepository orderLineItemRepository;

@MockBean
private InternalEventPublisher internalEventPublisher;

@SuppressWarnings("unchecked")
@Before
public void setup() {
    Mockito.when(orderRepository.findByOfsReferenceId("OFS:GMO:Z100002062-99")).thenReturn(null);
    OrderEntity savedOrder = new OrderEntity();
    savedOrder.setOrderId(1023);
    Mockito.when(orderRepository.save(Mockito.any(OrderEntity.class))).thenReturn(savedOrder);
    Iterable<OrderLineItemEntity> orderLineItemList = prepareOrderLineItemEntityIterable();
    Mockito.when(orderLineItemRepository.save(Mockito.any(Iterable.class))).thenReturn(orderLineItemList);
}

@Test
public void test() throws ParseException {
    FulfillmentOrder fulfillmentOrderRequestVO = new FulfillmentOrder();
    fulfillmentOrderRequestVO = buildFulfillmentOrder();
    String myMessage = "Order Created";
    ResponseEntity<ResponseOrderMessage> responseEntity = restTemplate.postForEntity("/fulfillmentprocessor/orders",
            fulfillmentOrderRequestVO, ResponseOrderMessage.class);
    ResponseOrderMessage responseOrderMessage = responseEntity.getBody();
    assertEquals(HttpStatus.CREATED, responseEntity.getStatusCode());
    assertEquals(myMessage, responseOrderMessage.getMessage());
}

【讨论】:

  • @mirmdasif, 排除在测试的情况下对我也不起作用(但 @ComponentScan 注释本身正在工作 - 例如 basePackages 有所不同)
【解决方案3】:

创建一个测试应用类

@SpringBootApplication
@ComponentScan(basePackages = "com.tesco.store.order.fulfillment.processor", excludeFilters = @Filter(type = FilterType.ASSIGNABLE_TYPE, classes = OrderReceiveEventConfiguration.class))
public class TestStoreOrderFulfillmentApplication {

public static void main(String[] args) {
    SpringApplication.run(StoreOrderFulfillmentApplication.class, args);
}
}

将以下配置注释添加到您的测试类

@SpringApplicationConfiguration(classes = TestStoreOrderFulfillmentApplication .class)

【讨论】:

    猜你喜欢
    • 2017-07-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多