Java 缓存上下文时MockIntegrationMessage不工作
我正在使用Java 缓存上下文时MockIntegrationMessage不工作,java,spring,spring-boot,spring-integration,spring-test,Java,Spring,Spring Boot,Spring Integration,Spring Test,我正在使用springintegration5.1.7.RELEASE,springboot2.1.7.RELEASE和springintegrationtest 5.0.11.RELEASE 作为测试的一部分,我正在尝试unittest一个IntegrationFlow,它执行对不同MessageHandlers的调用,因此我正在使用Spring集成测试中的MockIntegrationContext模拟它们 我的代码在Jenkins服务器上出现间歇性问题,这似乎与正在缓存的上下文有关。我有一
springintegration5.1.7.RELEASE
,springboot2.1.7.RELEASE
和springintegrationtest 5.0.11.RELEASE
作为测试的一部分,我正在尝试unittest
一个IntegrationFlow
,它执行对不同MessageHandlers
的调用,因此我正在使用Spring集成测试中的MockIntegrationContext
模拟它们
我的代码在Jenkins服务器上出现间歇性问题,这似乎与正在缓存的上下文有关。我有一个集成测试(@SpringBootTest
),没有模拟,还有一个测试类专门用于模拟IntegrationFlow
的MessageHandlers
如果集成测试在之前运行并且缓存了上下文,则由MockIntegrationContext
执行的设置似乎没有任何效果,并且调用底层service activator
,即使日志显示它已被取消订阅,而mock已被订阅到频道
以下是轮询器和句柄端点的定义:
@配置
公共类FlowConfig{
@豆子
公共集成流文件流(){
返回IntegrationFlows.from(
Files.inboundAdapter(新文件(fileDir)).autoCreateDirectory(true).preventDuplicates(false),
e->e.poller(Pollers.fixedDelay(pollingFrequency)).id(“fileInboundSourceEndpoint”).get()
...
.handle(fileParseHandler,e->e.id(“fileParseHandlerEndpoint”))
...
.get()
}
}
以下是测试设置:
@RunWith(SpringRunner.class)
@ContextConfiguration(class=FlowConfig.class)
@SpringIntegrationTest
@使能集成
公共类流测试{
@自动连线
MockIntegrationContext mockIntegrationCtx;
@试验
public void test_fileFlow()引发IOException{
mockIntegrationCtx.substituteMessageHandlerFor(“fileParseHandlerEndpoint”,
MockIntegration.mockMessageHandler().handleNextAndReply(m->m));
新文件(fileDir+“test”).createNewFile();
}
}
这是两组不同的日志,分别来自一个不成功的测试执行和一个成功的测试执行:
2019-09-09 15:17:02.059 INFO 14462 --- [ main] o.s.i.endpoint.EventDrivenConsumer : Removing {service-activator:fileParseHandlerEndpoint} as a subscriber to the 'fileFlow.channel#2' channel
2019-09-09 15:17:02.059 INFO 14462 --- [ main] o.s.integration.channel.DirectChannel : Channel 'org.springframework.context.support.GenericApplicationContext@51f95f0d.fileFlow.channel#2' has 0 subscriber(s).
2019-09-09 15:17:02.059 INFO 14462 --- [ main] o.s.i.endpoint.EventDrivenConsumer : stopped fileParseHandlerEndpoint
2019-09-09 15:17:02.062 INFO 14462 --- [ main] o.s.i.endpoint.EventDrivenConsumer : Adding {message-handler:fileParseHandlerEndpoint} as a subscriber to the 'fileFlow.channel#2' channel
2019-09-09 15:17:02.062 INFO 14462 --- [ main] o.s.integration.channel.DirectChannel : Channel 'org.springframework.context.support.GenericApplicationContext@51f95f0d.fileFlow.channel#2' has 1 subscriber(s).
2019-09-09 15:17:02.062 INFO 14462 --- [ main] o.s.i.endpoint.EventDrivenConsumer : started fileParseHandlerEndpoint
...
2019-09-09 15:17:03.731 DEBUG 14462 --- [ scheduling-1] o.s.i.file.FileReadingMessageSource : Added to queue: [/tmp/file]
2019-09-09 15:17:03.732 DEBUG 14462 --- [ scheduling-1] o.s.i.e.SourcePollingChannelAdapter : Poll resulted in Message: GenericMessage [payload=/tmp/file, headers={file_originalFile=/tmp/file, id=4323b036-4edd-019e-2c61-6917c7970767, file_name=file, file_relativePath=file, timestamp=1568056623732}]
...
2019-09-09 15:17:03.732 DEBUG 14462 --- [ scheduling-1] o.s.integration.channel.DirectChannel : preSend on channel 'fileFlow.channel#2', message: GenericMessage [payload=/tmp/file, headers={file_originalFile=/tmp/file, errorChannel=error_channel, id=af997a89-40d6-9024-65fc-7ab3883c329b, file_name=file, file_relativePath=file, timestamp=1568056623732}]
2019-09-09 15:17:03.732 DEBUG 14462 --- [ scheduling-1] o.s.i.handler.ServiceActivatingHandler : ServiceActivator for [org.springframework.integration.handler.MethodInvokingMessageProcessor@7b4acdc2] (fileParseHandlerEndpoint) received message: GenericMessage [payload=/tmp/file, headers={file_originalFile=/tmp/file, errorChannel=error_channel, id=af997a89-40d6-9024-65fc-7ab3883c329b, file_name=file, file_relativePath=file, timestamp=1568056623732}]
[Fatal Error] file:1:1: Premature end of file.
我知道可能有一个组合的@DirtiesContext
可以解决这个问题,但我仍然很难理解为什么MockIntegrationContext
无法从缓存的上下文中模拟MessageHandlers
是否有任何方法可以在不使用@DirtiesContext
的情况下修复此问题?首先,当您使用Spring Boot时,您需要依赖其版本管理。
此外,当使用Spring集成时,考虑使用<代码> Spring集成BOM<代码>导入。这样,您也不需要为单个模块指定版本
我的观点是,springintegrationcore
和springintegrationtest
有不同的版本。它们必须是一样的。否则,您可能会在运行时陷入混乱
现在谈谈这个问题
我认为这不是缓存问题
此测试套件的应用程序上下文开始与目标测试方法中的mockIntegrationCtx.substituteMessageHandlerFor()
之间存在竞争条件
问题来自这样一个事实:您从e.poller(Pollers.fixedDelay(pollingFrequency)
启动流。这是由TaskScheduler
在后台处理的,并为您的测试套件生成独立于主线程的消息。这就是您观察到意外行为的原因
您可以使用类似于autoStartup
操作的方法来解决此问题。@SpringIntegrationTest
为您提供了以下功能:
/**
* Specify a simple matching patterns ("xxx*", "*xxx", "*xxx*" or "xxx*yyy") for
* {@link org.springframework.integration.endpoint.AbstractEndpoint}
* bean names to mark them as {@code autoStartup = false}
* during context initialization.
* @return the endpoints name patterns to stop during context initialization
* @see IntegrationEndpointsInitializer
* @see org.springframework.util.PatternMatchUtils
*/
String[] noAutoStartup() default {};
所以,你喜欢这样:
@SpringIntegrationTest(noAutoStartup = "fileInboundSourceEndpoint")
然后在测试中自动连接通道适配器:
@自动连线
私有SourcePollingChannelAdapter fileInboundSourceEndpoint
然后在substituteMessageHandlerFor()之后启动它:
this.fileInboundSourceEndpoint.start();
谢谢!这应该可以解决问题。快速提问:我在同一测试套件上有多个测试。我是否应该在每次测试后停止SourcePollingChannelAdapter,并仅在设置模拟后重新启动它?如果在每个测试方法中使用相同的流,那么确实需要在每次测试后重新停止它。不过,我会将所有内容都保存在一个t中est方法:对于相同的SourcePollingChannelAdapter
,您有一个上下文,从性能角度来看,它更好。
this.fileInboundSourceEndpoint.start();