基于SpringBootTest的Spock规范的怪异行为

时间:2018-08-07 19:00:22

标签: spring-boot spring-integration spring-aop spock spring-test

鉴于我有一个Web应用程序,该应用程序还具有包含EvaluationHandler的Spring Integration管道,我想模拟业务处理失败。我创建了以下方面:

@Aspect
class FailureSimulator {
    @Before("execution(* *..*EvaluationHandler+.handle(..))")
    static void fail() {
        simulateBusinessProcessingFailure();
    }

    private static void simulateBusinessProcessingFailure() {
        throw new DataIntegrityViolationException("Simulated failure.");
    }
}

EvaluationHandlerorg.springframework.integration.dsl.support.GenericHandler

我创建了Spock规范,该规范导入了FailureSimulator

@SpringBootTest
@DirtiesContext
@Import(FailureSimulator)
class JmsSimulatedBusinessFailureSpec extends Specification {
    private static final String ACTIVEMQ_DLQ = "ActiveMQ.DLQ"
    @Autowired
    JmsTemplate jmsTemplate

    def "business processing failure"() {
        when: "I send a message to JMS upstream queue"

        jmsTemplate.convertAndSend(UPSTREAM_EVENT_QUEUE, message)

        then: "message is retried 6 times and parked in DLQ"
        jmsTemplate.setReceiveTimeout(25000L)
        def msg = jmsTemplate.receive(ACTIVEMQ_DLQ) as ActiveMQTextMessage
        msg != null
    }
}

当我单独运行此Specification时,它会起作用

但是,当我在基于Specification的另一个AbstractResourceProcessorSpec之后运行它时:

@SpringBootTest
abstract class AbstractResourceProcessorSpec extends Specification {}

测试失败,因为FailureSimulator没有加入。

即使我在日志中看到org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory - Found AspectJ method: public static void foo.FailureSimulator.fail(),也不会执行

我还查看了org.springframework.test.context.cache - Spring test ApplicationContext cache statistics日志,发现由于两个Specification上的注释不同,有2个上下文缓存了预期的内容

当我基于@DirtiesContextSpecification添加到AbstractResourceProcessorSpec并连续重新执行测试时,它会起作用。

ApplicationContext的{​​{1}}中缓存了ContextCache的情况一定要发生。还是其他的东西,但我不知道会是什么。

有人有什么线索吗?

已添加: 我比较了DefaultCacheAwareContextLoaderDelegate s和Specification中的bean,另外还有2个bean:JmsSimulatedBusinessFailureSpecorg.springframework.boot.test.context.ImportsContextCustomizer$ImportsCleanupPostProcessor

添加的示例: https://github.com/pmihalcin/weird-spring-boot-test-behavior

2 个答案:

答案 0 :(得分:0)

尝试将@MockBean用于EvaluationHandler,而不要使用Aspect模拟系统故障。

答案 1 :(得分:0)

来自Gitter频道的Andy Wilkinson的答案:

您的两个测试使用不同的配置,因此您正在运行两个应用程序上下文。 Spring框架在JVM的生命周期内缓存上下文(使上下文保持运行状态),以便可以重用它们。结果,当第二个测试运行时,您有两个消息侦听器容器(每个上下文一个)侦听同一队列。第一次测试的听众获胜。它没有建议的EvaluationHandler,因此不会发生模拟错误。在第一个测试中添加@DirtiesContext可以阻止它被缓存,因此测试框架在测试完成时将关闭上下文。然后,这允许第二个测试的侦听器检索消息,然后由建议的处理程序处理该消息,并发生模拟错误。

推荐: 您可以使用@DirtiesContext,也可以在模拟失败的情况下自定义某些内容,以便它使用其他队列? 或者,您可以在保持上下文缓存的同时在@BeforeClass@AfterClass中启动和停止侦听器容器