I met a problem in test of my application,I dont understand what i need to do if i want to replace ImapIdleChannelAdapter as it is written in the spring documentation
public class ImapConfiguration{
@Bean
ImapMailReceiver getReceiver() {
ImapMailReceiver receiver = new ImapMailReceiver(ImapConfig.getUri());
return receiver;
}
@Bean
ImapIdleChannelAdapter getAdapter(ImapMailReceiver receiver) {
ImapIdleChannelAdapter adapter = new InternalImapIdleChannelAdapter(receiver);
adapter.setAutoStartup(true);
return adapter;
}
@Bean
StandardIntegrationFlow getFlow(ImapIdleChannelAdapter adapter, GenericHandler handler) {
return IntegrationFlows.from(adapter)
.handle(handler)
.get();
}
}
In the spring integration documentation in the MockIntegration section says that "The MockIntegration factory provides an API to build mocks for Spring Integration beans that are parts of the integration flow (MessageSource, MessageProducer, MessageHandler, and MessageChannel).You can use the target mocks during the configuration phase as well as in the target test method to replace the real endpoints before performing verifications and assertions". I haven't found any examples using MessageProducer in the spring integration documentation and the Spring Integration Samples repository on github. I wrote test to try replace ImapIdleChannelAdapter
@SpringBootTest(classes = ImapConfiguration.class)
@Import({ReceiverTestConf.class})
@SpringIntegrationTest(noAutoStartup = "inboundChannelAdapter")
public class ImapMailReceiverTest {
@Captor
ArgumentCaptor<ReceivedMail> emailCaptor = ArgumentCaptor.forClass(ReceivedMail.class);
@MockBean
TestEmailHandler emailHandlerTestImpl;
@Autowired
TestImapReceiver imapReceiver;
@Autowired
MockIntegrationContext mockIntegrationContext;
@Test
@SneakyThrows
void receive() throws MessagingException {
Mockito.doNothing().when(emailHandlerTestImpl).handle(Mockito.any());
MessageSource<MimeMessage> message = () -> {
return new GenericMessage<>("testMessage");
};
this.mockIntegrationContext.substituteMessageSourceFor("imapIdleChannelAdapter", MockIntegration.mockMessageSource(message));
idleChannelAdapter.start();
await().atMost(1, TimeUnit.SECONDS).untilAsserted(() -> {
Mockito.verify(emailHandlerTestImpl, Mockito.times(1)).handle(emailCaptor.capture());
List<ReceivedMail> result = emailCaptor.getAllValues();
Assertions.assertEquals(1, result.size());
}
);
}
When I run the test, I am getting the exception.
Bean named 'imapIdleChannelAdapter' is expected to be of type 'org.springframework.integration.endpoint.SourcePollingChannelAdapter' but was actually of type 'com.test.emailadapter.imap.InternalImapIdleChannelAdapter'
org.springframework.beans.factory.BeanNotOfRequiredTypeException: Bean named 'imapIdleChannelAdapter' is expected to be of type 'org.springframework.integration.endpoint.SourcePollingChannelAdapter' but was actually of type 'com.test.emailadapter.imap.InternalImapIdleChannelAdapter'
at app//org.springframework.beans.factory.support.AbstractBeanFactory.adaptBeanInstance(AbstractBeanFactory.java:417)
at app//org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:398)
at app//org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:213)
at app//org.springframework.integration.test.context.MockIntegrationContext.substituteMessageSourceFor(MockIntegrationContext.java:217)
at app//org.springframework.integration.test.context.MockIntegrationContext.substituteMessageSourceFor(MockIntegrationContext.java:157)
at app//org.springframework.integration.test.context.MockIntegrationContext.substituteMessageSourceFor(MockIntegrationContext.java:142)
I believe the sentence in the doc needs some improvements. I definitely remember that there were some ambitions to be able mock everything in the flow. Therefore we mention over there a MessageProducer
and MessageChannel
as well. However in practice it turns out that we don't need to mock message channels since they can be supplied with ChannelInterceptor
to verify various interaction with the channel in the flow.
The MessageProducer
is also pointless to mock since you simply can emit a test message into the channel this producer is going to produce in the production. So, what you need so far is just stop this MessageProducer
before the test and deal with its channel in the test already.
I see you already do a proper noAutoStartup = "inboundChannelAdapter"
for your test class.
Since you don't have channel declared in your flow, the channel is auto-created by the framework with the pattern for name: [IntegrationFlow.beanName].channel#[channelNameIndex]
. So, the output channel for your IntegrationFlows.from(adapter)
is a DirectChannel
with a getFlow.channel#0
bean name.
Please, consider to raise a GH issue, so we will improve the doc for that MockIntegration
.