【问题标题】:Unit Test Spring Integration flow DSL单元测试 Spring 集成流 DSL
【发布时间】:2017-05-17 21:51:18
【问题描述】:

我正在尝试对一个简单的流程进行单元测试,它正在检查文件是否存在,然后执行一些额外的任务。

集成流

@Bean
public IntegrationFlow initiateAlarmAck() {
    return IntegrationFlows.from("processAckAlarmInputChannel")
            .handle((payload, headers) ->  {
                LOG.info("Received initiate ack alarm request at " + payload);
                File watermarkFile = getWatermarkFile();
                if(watermarkFile.isFile()){
                    LOG.info("Watermark File exists");
                    return true;
                }else{
                    LOG.info("File does not exists");
                    return false;
                }
            })
            .<Boolean, String>route(p -> fileRouterFlow(p))
            .get();
}
File getWatermarkFile(){
    return new File(eventWatermarkFile);
}

@Router
public String fileRouterFlow(boolean fileExits){
    if(fileExits)
        return "fileFoundChannel";
    else
        return "fileNotFoundChannel";
}

还有另一个集成流程,它从fileNotFoundChannel 中挑选一条消息并进行额外处理。我不想对这部分进行单元测试。在fileNotFoundChannel 上留言后,如何停止我的测试而不做进一步的测试?

@Bean
public IntegrationFlow fileNotFoundFlow() {
    return IntegrationFlows.from("fileNotFoundChannel")
            .handle((payload, headers) ->  {
                LOG.info("File Not Found");
                return payload;
            })
            .handle(this::getLatestAlarmEvent)
            .handle(this::setWaterMarkEventInFile)
            .channel("fileFoundChannel")
            .get();
}

单元测试类

@RunWith(SpringRunner.class)
@Import(AcknowledgeAlarmEventFlow.class)
@ContextConfiguration(classes = {AlarmAPIApplication.class})
@PropertySource("classpath:application.properties ")
public class AcknowledgeAlarmEventFlowTest {


    @Autowired
    ApplicationContext applicationContext;

    @Autowired
    RestTemplate restTemplate;

    @Autowired
    @Qualifier("processAckAlarmInputChannel")
    DirectChannel processAckAlarmInputChannel;

    @Autowired
    @Qualifier("fileNotFoundChannel")
    DirectChannel fileNotFoundChannel;

    @Autowired
    @Qualifier("fileFoundChannel")
    DirectChannel fileFoundChannel;

    @Mock
    File mockFile;

    @Test
    public void initiateAlarmAck_noFileFound_verifyMessageOnfileNotFoundChannel(){


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

        processAckAlarmInputChannel.send(MessageBuilder.withPayload(new Date()).build());
        MessageHandler mockMessageHandler = mock(MessageHandler.class);

        fileNotFoundChannel.subscribe(mockMessageHandler);
        verify(mockMessageHandler).handleMessage(any());
    }
}

提前致谢

【问题讨论】:

    标签: spring-integration spring-boot-test


    【解决方案1】:

    这正是我们使用now 实现MockMessageHandler 所做的场景。

    看起来你在嘲笑 fileNotFoundFlow 时采取了正确的方式来防止进一步的行动,但错过了一些简单的技巧:

    您必须在fileNotFoundChannel 上使用真正的.handle((payload, headers) ) 端点stop()。这样它就会取消订阅频道并且不再消费消息。为此,我建议这样做:

    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();
        }
    
    }
    
    }
    

    【讨论】:

    • 更正了测试,发现“fileNotFoundChannel”是直接通道。我将“fileNotFoundChannel”更改为 SubscribableChannel,以便测试用例可以让 mockMessageHandler 订阅该频道。然而,控件并没有来验证测试用例中的行。我确实看到在“fileNotFoundChannel”上调用了 preSend
    • 我在我的答案中添加了完整的工作示例。确保在模拟之前已停止端点。否则,您的fileNotFoundChannel 有多个订阅者,第一个订阅者会收到第一条消息。见:docs.spring.io/spring-integration/reference/html/… 关于LoadBalancingStrategy
    • 感谢您的指导。我在一个测试类中有一堆测试,它们分别测试端点。它们在单独测试时运行良好,但在单个测试类中运行时,其中一些失败了。对于每个停止终点的测试,我都必须在测试结束时开始。此外,当模拟处理程序订阅频道时,我必须在测试结束时取消订阅。这对于在单个测试类中运行所有测试是必要的。
    • 确实如此:如果您订阅模拟,您最终必须取消订阅。这就是为什么我们在测试框架中有resetBeans() 选项
    • 我们可以将@SpringBootTest@SpringIntegrationTest 一起使用吗?令人惊讶的是,文档省略了这一点。
    猜你喜欢
    • 1970-01-01
    • 2017-06-28
    • 1970-01-01
    • 1970-01-01
    • 2010-09-21
    • 1970-01-01
    • 2019-07-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多