单元测试 Spring 集成流程 DSL
Unit Test Spring Integration flow DSL
我正在尝试对检查文件是否存在的简单流程进行单元测试,然后执行一些其他任务。
集成流
@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();
}
单元测试Class
@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());
}
}
提前致谢
这正是我们正在 now 使用 MockMessageHandler
实现的场景。
看起来你用 mocking 来防止进一步的操作是正确的 fileNotFoundFlow
,但是错过了一些简单的技巧:
您必须 stop()
那个 fileNotFoundChannel
上的真实 .handle((payload, headers) )
端点。这样它将取消订阅频道并且不再使用消息。为此,我建议这样做:
return IntegrationFlows.from("fileNotFoundChannel")
.handle((payload, headers) -> {
LOG.info("File Not Found");
return payload;
}, e -> e.id("fileNotFoundEndpoint"))
并在测试中class
@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();
}
}
}
我正在尝试对检查文件是否存在的简单流程进行单元测试,然后执行一些其他任务。
集成流
@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();
}
单元测试Class
@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());
}
}
提前致谢
这正是我们正在 now 使用 MockMessageHandler
实现的场景。
看起来你用 mocking 来防止进一步的操作是正确的 fileNotFoundFlow
,但是错过了一些简单的技巧:
您必须 stop()
那个 fileNotFoundChannel
上的真实 .handle((payload, headers) )
端点。这样它将取消订阅频道并且不再使用消息。为此,我建议这样做:
return IntegrationFlows.from("fileNotFoundChannel")
.handle((payload, headers) -> {
LOG.info("File Not Found");
return payload;
}, e -> e.id("fileNotFoundEndpoint"))
并在测试中class
@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();
}
}
}