Spring Integration тестирует поток Files.inboundAdapter

У меня есть этот поток, который я пытаюсь проверить, но ничего не работает, как ожидалось. Сам поток работает хорошо, но тестирование кажется немного сложным. Это мой поток:

@Configuration
@RequiredArgsConstructor
public class FileInboundFlow {
    private final ThreadPoolTaskExecutor threadPoolTaskExecutor;
    private String filePath;
    
    @Bean
    public IntegrationFlow fileReaderFlow() {
      
        return IntegrationFlows.from(Files.inboundAdapter(new File(this.filePath))
                                .filterFunction(...)
                                .preventDuplicates(false),
                        endpointConfigurer -> endpointConfigurer.poller(
                             Pollers.fixedDelay(500)
                                .taskExecutor(this.threadPoolTaskExecutor)
                                .maxMessagesPerPoll(15)))
                .transform(new UnZipTransformer())
                .enrichHeaders(this::headersEnricher)
                .transform(Message.class, this::modifyMessagePayload)
                .route(Map.class, this::channelsRouter)
                .get();
    }

   private String channelsRouter(Map<String, File> payload) {
          boolean isZip = payload.values()
                .stream()
                .anyMatch(file -> isZipFile(file));

        return isZip ? ZIP_CHANNEL : XML_CHANNEL; // ZIP_CHANNEL and XML_CHANNEL are PublishSubscribeChannel
    }
  

    @Bean
    public SubscribableChannel xmlChannel() {
        var channel = new PublishSubscribeChannel(this.threadPoolTaskExecutor);
        channel.setBeanName(XML_CHANNEL);
        return channel;
    }
    
    @Bean
    public SubscribableChannel zipChannel() {
        var channel = new PublishSubscribeChannel(this.threadPoolTaskExecutor);
        channel.setBeanName(ZIP_CHANNEL);
        return channel;
    }

   //There is a @ServiceActivator on each channel

    @ServiceActivator(inputChannel = XML_CHANNEL)
    public void handleXml(Message<Map<String, File>> message) {
        ...
    }

    @ServiceActivator(inputChannel = ZIP_CHANNEL)
    public void handleZip(Message<Map<String, File>> message) {
        ...
    }

   //Plus an @Transformer on the XML_CHANNEL

    @Transformer(inputChannel = XML_CHANNEL, outputChannel = BUS_CHANNEL)
    private List<BusData> xmlFileToIngestionMessagePayload(Map<String, File> xmlFilesByName) {
        return xmlFilesByName.values()
                .stream()
                .map(...)
                .collect(Collectors.toList());
    }
}

Я хотел бы протестировать несколько случаев, первый — проверка полезной нагрузки сообщения, опубликованного на каждом канале после окончания fileReaderFlow. Итак, я определил этот тестовый класс:

@SpringBootTest
@SpringIntegrationTest
@ExtendWith(SpringExtension.class)
class FileInboundFlowTest {
    
    @Autowired
    private MockIntegrationContext mockIntegrationContext;

    @TempDir
    static Path localWorkDir;

    @BeforeEach
    void setUp() {
        copyFileToTheFlowDir(); // here I copy a file to trigger the flow
    }

   
    @Test
    void checkXmlChannelPayloadTest() throws InterruptedException {
       
       Thread.sleep(1000); //waiting for the flow execution

        PublishSubscribeChannel xmlChannel = this.getBean(XML_CHANNEL, PublishSubscribeChannel.class); // I extract the channel to listen to the message sent to it.

        xmlChannel.subscribe(message -> {
            assertThat(message.getPayload()).isInstanceOf(Map.class); // This is never executed
        });
    }
}

Как и ожидалось, этот тест не работает, потому что assertThat(message.getPayload()).isInstanceOf(Map.class); никогда не выполняется. Прочитав документация, я не нашел подсказки, которая помогла бы мне решить эту проблему. Любая помощь будет оценена по достоинству! Большое спасибо

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
22
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Во-первых, channel.setBeanName(XML_CHANNEL); не влияет на целевой компонент. Вы делаете это на этапе создания компонента, и контейнер внедрения зависимостей ничего не знает об этом параметре: он просто не консультируется с ним. Если вы действительно хотите продиктовать XML_CHANNEL имя компонента, вам лучше изучить атрибут @Bean(name).

Проблема в тесте в том, что вы упускаете факт асинхронной логики потока. Это Files.inboundAdapter() работает, если полностью другой поток и выдает сообщения за пределами вашего тестового метода. Таким образом, даже если вы смогли подписаться на канал вовремя, до того, как на него будет отправлено какое-либо сообщение, это не означает, что ваш тест будет работать правильно: assertThat() будет выполняться в другом потоке. Поэтому нет реального отчета JUnit для вашего контекста метода тестирования.

Итак, что я предлагаю сделать, это:

  1. Остановите Files.inboundAdapter() в начале теста перед любой настройкой, которую вы хотели бы выполнить в тесте. Или, по крайней мере, не помещайте файлы в этот filePath, чтобы адаптер канала не выдавал сообщения.
  2. Возьмите канал из контекста приложения и, если хотите, подпишитесь или используйте ChannelInterceptor.
  3. Имейте асинхронный барьер, например. CountDownLatch передать этому подписчику.
  4. Запустите адаптер канала или поместите файл в каталог для сканирования.
  5. Дождитесь асинхронного барьера, прежде чем проверять какое-либо значение или состояние.

Большое спасибо, я только что попробовал ваши предложения, и все работает как шарм. Вопрос о вашем первом предложении, как я могу остановить/запустить Files.inboundAdapter()?

akuma8 04.05.2022 12:16

endpointConfigurer имеет атрибут id(). Таким образом, вы можете получить Lifecycle bean-компонент и вызвать его stop(), а затем start() соответственно. В противном случае вы можете использовать @SpringIntegrationTest(noAutoStartup) с этим id, чтобы остановить его перед набором тестов. Тогда вам все равно нужно запустить его вручную, когда все настройки будут выполнены.

Artem Bilan 04.05.2022 16:36

Другие вопросы по теме

Похожие вопросы

Использование Rest Assured для тестирования по сравнению с использованием Rest Assured и TestNG. Может кто-нибудь объяснить разницу между ними?
Не удалось загрузить модуль "имя проекта"
Почему @testing-library/user-event не может взаимодействовать с элементами ввода?
Как я могу проверить флажок MUI без метки, используя data-testid?
Как я могу выбрать элемент из раскрывающегося списка, когда элемент параметра не взаимодействует через селен/питон?
Как получить количество запущенных приспособлений в тесте pytest
Cypress Test - файлы функций огурца, выдающие ошибку «Вам может понадобиться соответствующий загрузчик для обработки этого файла» при запуске тестов кипариса в машинописном тексте
Как запустить тестовые примеры для бинарника в Makefile
Добавить пользовательский атрибут данных в компонент Option
Переменная шаблона модуля возвращает неопределенное значение в тесте?