鉴于我有一个Web应用程序,该应用程序还具有包含EvaluationHandler
的Spring Integration管道,我想模拟业务处理失败。我创建了以下方面:
@Aspect
class FailureSimulator {
@Before("execution(* *..*EvaluationHandler+.handle(..))")
static void fail() {
simulateBusinessProcessingFailure();
}
private static void simulateBusinessProcessingFailure() {
throw new DataIntegrityViolationException("Simulated failure.");
}
}
而EvaluationHandler
是org.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个上下文缓存了预期的内容
当我基于@DirtiesContext
将Specification
添加到AbstractResourceProcessorSpec
并连续重新执行测试时,它会起作用。
在ApplicationContext
的{{1}}中缓存了ContextCache
的情况一定要发生。还是其他的东西,但我不知道会是什么。
有人有什么线索吗?
已添加:
我比较了DefaultCacheAwareContextLoaderDelegate
s和Specification
中的bean,另外还有2个bean:JmsSimulatedBusinessFailureSpec
和org.springframework.boot.test.context.ImportsContextCustomizer$ImportsCleanupPostProcessor
添加的示例: https://github.com/pmihalcin/weird-spring-boot-test-behavior
答案 0 :(得分:0)
尝试将@MockBean
用于EvaluationHandler
,而不要使用Aspect模拟系统故障。
答案 1 :(得分:0)
来自Gitter频道的Andy Wilkinson的答案:
您的两个测试使用不同的配置,因此您正在运行两个应用程序上下文。 Spring框架在JVM的生命周期内缓存上下文(使上下文保持运行状态),以便可以重用它们。结果,当第二个测试运行时,您有两个消息侦听器容器(每个上下文一个)侦听同一队列。第一次测试的听众获胜。它没有建议的EvaluationHandler
,因此不会发生模拟错误。在第一个测试中添加@DirtiesContext
可以阻止它被缓存,因此测试框架在测试完成时将关闭上下文。然后,这允许第二个测试的侦听器检索消息,然后由建议的处理程序处理该消息,并发生模拟错误。
推荐:
您可以使用@DirtiesContext
,也可以在模拟失败的情况下自定义某些内容,以便它使用其他队列?
或者,您可以在保持上下文缓存的同时在@BeforeClass
和@AfterClass
中启动和停止侦听器容器