Spring integration 单元测试Spring集成流DSL

Spring integration 单元测试Spring集成流DSL,spring-integration,spring-boot-test,Spring Integration,Spring Boot Test,我试图对一个简单的流进行单元测试,在这个流中检查文件的存在,然后执行一些额外的任务 积分流 @Bean 公共集成流启动器Armack(){ 返回IntegrationFlows.from(“processAckAlarmInputChannel”) .handle((有效负载、标题)->{ LOG.info(“在“+有效负载”处收到启动确认报警请求); File watermarkFile=getWatermarkFile(); if(watermarkFile.isFile()){ LOG.i

我试图对一个简单的流进行单元测试,在这个流中检查文件的存在,然后执行一些额外的任务

积分流

@Bean
公共集成流启动器Armack(){
返回IntegrationFlows.from(“processAckAlarmInputChannel”)
.handle((有效负载、标题)->{
LOG.info(“在“+有效负载”处收到启动确认报警请求);
File watermarkFile=getWatermarkFile();
if(watermarkFile.isFile()){
LOG.info(“存在水印文件”);
返回true;
}否则{
LOG.info(“文件不存在”);
返回false;
}
})
.route(p->fileRouterFlow(p))
.get();
}
文件getWatermarkFile(){
返回新文件(eventWatermarkFile);
}
@路由器
公共字符串fileRouterFlow(布尔文件出口){
如果(文件退出)
返回“fileFoundChannel”;
其他的
返回“fileNotFoundChannel”;
}
还有另一个集成流,它从
fileNotFoundChannel
中拾取消息并执行附加处理。我不想对这部分进行单元测试。如何停止测试,使其不再继续,并在将消息置于
fileNotFoundChannel
后停止

@Bean
公共集成流文件NotFoundFlow(){
返回IntegrationFlows.from(“fileNotFoundChannel”)
.handle((有效负载、标题)->{
LOG.info(“未找到文件”);
返回有效载荷;
})
.handle(this::getLatestAlarmEvent)
.handle(this::setWaterMarkEventInFile)
.channel(“fileFoundChannel”)
.get();
}
单元测试类

@RunWith(SpringRunner.class)
@导入(AcknowledgeeAlarmEventFlow.class)
@ContextConfiguration(类={AlarmAPIApplication.class})
@PropertySource(“类路径:application.properties”)
公共类AcknowledgeeAlarmEventFlowTest{
@自动连线
应用上下文应用上下文;
@自动连线
rest模板rest模板;
@自动连线
@限定符(“processAckAlarmInputChannel”)
DirectChannel processAckAlarmInputChannel;
@自动连线
@限定符(“fileNotFoundChannel”)
DirectChannel fileNotFoundChannel;
@自动连线
@限定符(“fileFoundChannel”)
DirectChannel fileFoundChannel;
@嘲弄
文件模拟文件;
@试验
public void initiateAlarmAck\u noFileFound\u verifyMessageOnfileNotFoundChannel(){
AcknowledgeeAlarmEventFlow.ProcessAcknowledgeeAlarmGateway=applicationContext.getBean(AcknowledgeeAlarmEventFlow.ProcessAcknowledgeeAlarmGateway.class);
gateway.initiateAcknowledgeAlarm();
processAckAlarmInputChannel.send(MessageBuilder.withPayload(新日期()).build());
MessageHandler mockMessageHandler=mock(MessageHandler.class);
订阅(mockMessageHandler);
验证(mockMessageHandler).handleMessage(any());
}
}

提前感谢

这正是我们使用
MockMessageHandler
实现所做的

看起来您在该
fileNotFoundFlow
中正确地进行了模拟,以防止进一步的操作,但忽略了一些简单的技巧:

您必须
stop()
fileNotFoundChannel
上的实际
.handle((有效负载、头))
端点。这样,它将从该频道取消订阅,不再使用消息。为此,我建议:

return IntegrationFlows.from("fileNotFoundChannel")
.handle((payload, headers) ->  {
  LOG.info("File Not Found");
  return payload;
}, e -> e.id("fileNotFoundEndpoint"))
在测试课上

@Autowired
@Qualifier("fileNotFoundEndpoint")
AbstractEndpoint fileNotFoundEndpoint;
 ...

@Test
public void initiateAlarmAck_noFileFound_verifyMessageOnfileNotFoundChannel(){
  this.fileNotFoundEndpoint.stop();

  MessageHandler mockMessageHandler = mock(MessageHandler.class);

  fileNotFoundChannel.subscribe(mockMessageHandler);


  AcknowledgeAlarmEventFlow.ProcessAcknowledgeAlarmGateway gateway = applicationContext.getBean(AcknowledgeAlarmEventFlow.ProcessAcknowledgeAlarmGateway.class);
  gateway.initiateAcknowledgeAlarm();

  processAckAlarmInputChannel.send(MessageBuilder.withPayload(new Date()).build());
  verify(mockMessageHandler).handleMessage(any());
}
请注意,在发送信息到频道之前,我是如何移动嘲弄和订阅的

有了新的
MockIntegrationContext
功能,框架将为您解决这些问题。但是是的。。。与任何单元测试一样,模拟必须在交互之前准备好

更新

工作样本:

@RunWith(SpringRunner.class)
@ContextConfiguration
public class MockMessageHandlerTests {

@Autowired
private SubscribableChannel fileNotFoundChannel;

@Autowired
private AbstractEndpoint fileNotFoundEndpoint;

@Test
@SuppressWarnings("unchecked")
public void testMockMessageHandler() {
    this.fileNotFoundEndpoint.stop();

    MessageHandler mockMessageHandler = mock(MessageHandler.class);

    this.fileNotFoundChannel.subscribe(mockMessageHandler);

    GenericMessage<String> message = new GenericMessage<>("test");
    this.fileNotFoundChannel.send(message);

    ArgumentCaptor<Message<?>> messageArgumentCaptor = ArgumentCaptor.forClass(Message.class);

    verify(mockMessageHandler).handleMessage(messageArgumentCaptor.capture());

    assertSame(message, messageArgumentCaptor.getValue());
}

@Configuration
@EnableIntegration
public static class Config {

    @Bean
    public IntegrationFlow fileNotFoundFlow() {
        return IntegrationFlows.from("fileNotFoundChannel")
        .<Object>handle((payload, headers) -> {
            System.out.println(payload);
            return payload;
        }, e -> e.id("fileNotFoundEndpoint"))
        .channel("fileFoundChannel")
        .get();
    }

}

}
@RunWith(SpringRunner.class)
@上下文配置
公共类MockMessageHandlerTests{
@自动连线
专用订阅频道fileNotFoundChannel;
@自动连线
私有抽象端点fileNotFoundEndpoint;
@试验
@抑制警告(“未选中”)
public void testMockMessageHandler(){
this.fileNotFoundEndpoint.stop();
MessageHandler mockMessageHandler=mock(MessageHandler.class);
this.fileNotFoundChannel.subscribe(mockMessageHandler);
GenericMessage=新的GenericMessage(“测试”);
this.fileNotFoundChannel.send(消息);

ArgumentCaptor更正了测试,并意识到“fileNotFoundChannel”是一个直接通道。我更改了“fileNotFoundChannel”要订阅通道,以便测试用例可以让mockMessageHandler订阅该通道。但是控件不会来验证测试用例中的行。我确实看到在“fileNotFoundChannel”上调用了preSend。我在回答中添加了完全工作的示例。请确保在模拟之前已停止端点。否则,
fileNot FoundChannel
有多个订户,第一个订户将捕获第一条消息。请参阅:about
LoadBalancingStrategy
感谢您的指导。我在一个测试类中有一系列测试,分别测试端点。单独测试时,它们运行良好,但在单个测试类中运行时,其中一些测试失败ng.对于每个停止端点的测试,我必须在测试结束时开始。此外,当模拟处理程序订阅某个频道时,我必须在测试结束时取消订阅。这对于在单个测试类中运行所有测试来说都是必要的。这是真的:如果你订阅模拟,你必须在最后取消订阅。这就是为什么我们的tes中有t framework
resetBeans()
option我们可以将
@springbootest
@SpringIntegrationTest
一起使用吗?文档竟然忽略了这一点。