我最近实施了一个小项目,在该项目中,我们必须轮询文件夹中的新文件,然后在文件内容上触发服务流。
Spring Integration非常适合此要求,因为它带有一个通道适配器 ,该适配器可以扫描文件夹中的新文件,然后通过消息传递流程获取文件。
本文的目的是研究如何测试文件轮询器流。
首先考虑使用以下Spring集成配置实现的简单流程:
<beans:beans xmlns="http://www.springframework.org/schema/integration".....<channel id="fileChannel"></channel><channel id="processedFileChannel"></channel><int-file:inbound-channel-adapter directory="${inbound.folder}" channel="fileChannel" filename-pattern="*.*"><poller fixed-delay="5000"></poller></int-file:inbound-channel-adapter><service-activator input-channel="fileChannel" ref="fileHandlerService" method="handle" output-channel="processedFileChannel"></service-activator><logging-channel-adapter id="loggingChannelAdapter" channel="processedFileChannel"></logging-channel-adapter><beans:bean name="fileHandlerService" class="files.RealFileHandlingService"/><context:property-placeholder properties-ref="localProps" local-override="true"/><util:properties id="localProps"></util:properties>
</beans:beans>
在图中更好地表示了这一点:
流程简单测试
现在要测试此流程,我的第一种方法是将示例文件放入类路径中的文件夹中,在测试过程中动态发现并使用此文件夹名称,并将最终消息写入测试通道,并对进入该通道的消息进行断言。 这是组成原始Spring配置的测试配置的样子:
<beans:beans xmlns="http://www.springframework.org/schema/integration"....<beans:import resource="si-fileprocessing.xml"/><util:properties id="localProps"><beans:prop key="inbound.folder">#{new java.io.File(T(java.io.File).getResource("/samplefolder/samplefile.txt").toURI()).parent}</beans:prop></util:properties><channel id="testChannel"><queue/></channel><bridge id="loggingChannelAdapter" input-channel="processedFileChannel" output-channel="testChannel"></bridge>
</beans:beans>
测试看起来像这样:
@Autowired @Qualifier("testChannel") PollableChannel testChannel;@Test
public void testService() throws Exception{Message<?> message = this.testChannel.receive(5000);assertThat((String)message.getPayload(), equalTo("Test Sample file content"));
}
这可以很好地工作,尤其要注意,可以使用Spring-EL表达式在配置中完全提供路径:
#{new java.io.File(T(java.io.File).getResource("/samplefolder/samplefile.txt").toURI()).parent}
模拟服务
现在,进一步介绍一下,如果我想模拟正在处理文件的服务(files.RealFileHandlingService),该怎么办。 一旦实现了模拟,这里就会出现一个问题。 注入模拟服务的一种方法是使用Mockito和它提供的帮助程序功能,以使用Spring配置文件通过这种方式创建模拟:
<beans:bean name="fileHandlerService" factory-method="mock" class="org.mockito.Mockito"><beans:constructor-arg value="files.FileHandlingService"></beans:constructor-arg>
</beans:bean>
创建此模拟bean之后,可以通过以下方式在junit的@Before注释方法中添加模拟行为:
@Before
public void setUp() {when(fileHandlingServiceMock.handle((File)(anyObject()))).thenReturn("Completed File Processing");
}@Test
public void testService() throws Exception{Message<?> message = this.testChannel.receive(5000);assertThat((String)message.getPayload(), equalTo("Completed File Processing"));
}
如果现在重复测试,令人惊讶的是它将失败,原因是–在调用Junit的@Before方法时,Spring应用程序上下文已完全初始化,并且轮询进入文件夹的文件的轮询器在模拟之前被触发行为被添加,因此,如果没有正确的模拟服务行为,测试将失败。
我确定还有其他修复程序,但是对我有用的修复程序实际上是控制扫描哪个文件夹以及在什么时候将文件放置在文件夹中以触发流。 这很大程度上基于我在Spring Integration项目本身中看到的一些测试 。 诀窍是先使用Spring config创建一个临时文件夹,然后将该文件夹设置为轮询文件夹:
<beans:bean id="temp" class="org.junit.rules.TemporaryFolder"init-method="create" destroy-method="delete"/><beans:bean id="inputDirectory" class="java.io.File"><beans:constructor-arg value="#{temp.newFolder('sitest').path}"/>
</beans:bean> <util:properties id="localProps"><beans:prop key="inbound.folder">#{inputDirectory.getAbsolutePath()}</beans:prop>
</util:properties>
现在,仅在测试运行期间将文件放置在临时文件夹中,这样@Before注释方法就有机会向模拟添加行为,并且可以明确断言模拟的行为:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("si-test.xml")
public class FileHandlingFlowTest {@Autowired @Qualifier("testChannel") private PollableChannel testChannel;@Autowired private FileHandlingService fileHandlingServiceMock;@Autowired @Qualifier("inputDirectory") private File inputDirectory;@Beforepublic void setUp() {when(fileHandlingServiceMock.handle((File)(anyObject()))).thenReturn("Completed File Processing");}@Testpublic void testService() throws Exception{Files.copy(new File(this.getClass().getResource("/samplefolder/samplefile.txt").toURI()), new File(inputDirectory, "samplefile.txt"));Message<?> message = this.testChannel.receive(5000);assertThat((String)message.getPayload(), equalTo("Completed File Processing"));}
}
翻译自: https://www.javacodegeeks.com/2013/05/spring-integration-file-polling-and-tests.html