Недавно я реализовал небольшой проект, в котором мы должны были опрашивать папку для новых файлов, а затем запускать поток обслуживания для содержимого файла.
Spring Integration идеально подходит для этого требования, поскольку поставляется с канальным адаптером, который может сканировать папку на наличие новых файлов и затем передавать файл через поток сообщений.
Цель этой конкретной статьи — узнать, как можно протестировать поток файловых программ.
Для начала рассмотрим простой поток, реализованный с использованием следующей конфигурации интеграции Spring:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
|
..... <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> |
Это лучше представлено на диаграмме:
Простое тестирование потока
Теперь, чтобы протестировать этот поток, мой первый подход состоял в том, чтобы поместить образец файла в папку в classpath, динамически обнаружить и использовать это имя папки во время теста и записать окончательное сообщение в тестовый канал и подтвердить сообщения, поступающие в этот канал. , Вот как выглядит тестовая конфигурация, которая составляет исходную конфигурацию Spring:
|
01
02
03
04
05
06
07
08
09
10
11
12
|
.... <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> |
и тест выглядит так:
|
1
2
3
4
5
6
7
|
@Autowired @Qualifier("testChannel") PollableChannel testChannel;@Testpublic void testService() throws Exception{ Message<?> message = this.testChannel.receive(5000); assertThat((String)message.getPayload(), equalTo("Test Sample file content"));} |
Это работает аккуратно, особенно обратите внимание, что путь может быть полностью указан в конфигурации с использованием выражения Spring-EL:
|
1
|
#{new java.io.File(T(java.io.File).getResource("/samplefolder/samplefile.txt").toURI()).parent} |
Макет Сервиса
Теперь, если пойти немного дальше, что если я захочу издеваться над сервисом, обрабатывающим файл (files.RealFileHandlingService). Здесь есть проблема, которая станет понятной после того, как макет будет реализован. Подход к внедрению в mock-сервисе заключается в использовании Mockito и вспомогательной функции, которую он предоставляет для создания mock-файла таким образом с помощью файла конфигурации Spring:
|
1
2
3
|
<beans:bean name="fileHandlerService" factory-method="mock" class="org.mockito.Mockito"> <beans:constructor-arg value="files.FileHandlingService"></beans:constructor-arg></beans:bean> |
Как только этот фиктивный бин создан, его поведение можно добавить в аннотированный метод junit @Before следующим образом:
|
01
02
03
04
05
06
07
08
09
10
|
@Beforepublic void setUp() { when(fileHandlingServiceMock.handle((File)(anyObject()))).thenReturn("Completed File Processing");}@Testpublic void testService() throws Exception{ Message<?> message = this.testChannel.receive(5000); assertThat((String)message.getPayload(), equalTo("Completed File Processing"));} |
Если тест повторяется сейчас, неожиданно он не пройдёт, и причина в том, что контекст приложения Spring полностью инициализируется к тому времени, когда вызов приходит к методу @Before в Junit, и ПО, проверяющее файл, поступающий в папку, запускается ПЕРЕД макетом добавлено поведение и, следовательно, без корректного поведения фиктивной службы тест не пройден.
Я уверен, что есть и другие исправления, но исправление, которое работало для меня, состояло в том, чтобы по существу контролировать, какая папка сканируется и в какой момент файл помещается в папку для запуска потока. Это в значительной степени основано на некоторых тестах, которые я видел в самом проекте Spring Integration. Хитрость заключается в том, чтобы сначала создать временную папку, используя конфигурацию Spring, и установить ее в качестве папки опроса:
|
01
02
03
04
05
06
07
08
09
10
|
<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 получает возможность добавить поведение к макету, и смоделированное поведение может быть четко подтверждено:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
|
@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; @Before public void setUp() { when(fileHandlingServiceMock.handle((File)(anyObject()))).thenReturn("Completed File Processing"); } @Test public 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")); }} |
