这是Spring Integration Executor Channel using annotations code sample的后续问题。
我正试图通过在“公共频道”中发布消息来测试红色突出显示的框。并从信息中设置的REPLY_CHANNEL中读取。
'共同频道'是一个发布订阅频道。 REPLY_CHANNEL是一个QueueChannel。
由于这是一个JUnit测试,我已经模拟了jdbcTemplate,datasource和Impl以忽略任何数据库调用。
我的问题是: 当我将消息发布到'公共频道'时,我在REPLY_CHANNEL上没有收到任何消息。 junit一直在等待回复。
我应该更改什么才能在REPLY_CHANNEL上获得回复?
@RunWith(SpringRunner.class)
@SpringBootTest
@ContextConfiguration(loader = AnnotationConfigContextLoader.class) --------- 1
@ActiveProfiles("test")
public class QueuetoQueueTest {
@Configuration
static class ContextConfiguration { ------------------------------------- 2
@Bean(name = "jdbcTemplate")
public JdbcTemplate jdbcTemplate() {
JdbcTemplate jdbcTemplateMock = Mockito.mock(JdbcTemplate.class);
return jdbcTemplateMock;
}
@Bean(name = "dataSource")
public DataSource dataSource() {
DataSource dataSourceMock = Mockito.mock(DataSource.class);
return dataSourceMock;
}
@Bean(name = "entityManager")
public EntityManager entityManager() {
EntityManager entityManagerMock = Mockito.mock(EntityManager.class);
return entityManagerMock;
}
@Bean(name = "ResponseChannel")
public QueueChannel getReplyQueueChannel() {
return new QueueChannel();
}
//This channel serves as the 'common channel' in the diagram
@Bean(name = "processRequestSubscribableChannel")
public MessageChannel getPublishSubscribeChannel() {
return new PublishSubscribeChannel();
}
}
@Mock
DBStoreDaoImpl dbStoreDaoImpl;
@Test
public void testDBConnectivity() {
Assert.assertTrue(true);
}
@InjectMocks -------------------------------------------------------------- 3
StoretoDBConfig storetoDBConfig = new StoretoDBConfig();
@Autowired
@Qualifier("ResponseChannel")
QueueChannel ResponseChannel;
@Autowired
@Qualifier("processRequestSubscribableChannel")
MessageChannel processRequestSubscribableChannel;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
}
@Test
public void outboundtoQueueTest() {
try {
when(dbStoreDaoImpl.storeToDB(any()))
.thenReturn(1); ----------------------------------------------- 4
//create message
Message message = (Message<String>) MessageBuilder
.withPayload("Hello")
.setHeader(MessageHeaders.REPLY_CHANNEL, ResponseChannel)
.build();
//send message
processRequestSubscribableChannel.send(message);
System.out
.println("Listening on InstructionResponseHandlertoEventProcessorQueue");
//wait for response on reply channel
Message<?> response = ResponseChannel.receive(); ----------------------- 5
System.out.println("***************RECEIVED: "
+ response.toString());
} catch (Exception e) {
e.printStackTrace();
}
}
}
加载&#39; ContextConfiguration&#39;对于JUnit,以便不访问DB。
这是按照https://spring.io/blog/2011/06/21/spring-3-1-m2-testing-with-configuration-classes-and-profiles
在config类中,我们模拟jdbcTemplate,dataSource,entityManager并定义&#39;公共频道&#39;请求发布的位置和ResponseChannel。
将jdbcTemplate,dataSource模拟注入StoretoDBConfig,以便不会命中数据库
模拟DaoImpl类,以便忽略数据库调用
这里的测试块因为REPLY_CHANNEL没有响应
更新代码:
Code inside 5 (the class that reads from common channel):
@Configuration
class HandleRequestConfig {
//Common channel - refer diagram
@Autowired
PublishSubscribeChannel processRequestSubscribableChannel;
//Step 9 - This channel is used to send queue to the downstream system
@Autowired
PublishSubscribeChannel forwardToExternalSystemQueue;
public void handle() {
IntegrationFlows.from("processRequestSubscribableChannel") // Read from 'Common channel'
.wireTap(flow->flow.handle(msg -> System.out.println("Msg received on processRequestSubscribableChannel"+ msg.getPayload())))
.handle(RequestProcessor,"validateMessage") // Perform custom business logic - no logic for now, return the msg as is
.wireTap(flow->flow.handle(msg -> System.out.println("Msg received on RequestProcessor"+ msg.getPayload())))
.channel("forwardToExternalSystemQueue"); // Post to 'Channel to another system'
}
}
//Code inside step 8 - 'Custom Business Logic'
@Configuration
class RequestProcessor {
public Message<?> validateMessage(Message<?> msg) {
return msg;
}
}
我想要实现的目标: 我有针对业务逻辑的各个junit测试用例。我正在尝试测试,当请求被发布到“公共频道”时,响应会在&#39;频道上收到另一个系统&#39;。
为什么我不能使用原始的ApplicationContext:因为它连接到数据库,我不希望我的JUnit连接到数据库或使用嵌入式数据库。我希望忽略对DB的任何调用。
我已将回复频道设置为“响应频道”,而不是“自定义业务逻辑”&#39;将其回复发送给ResponseChannel&#39;?
如果我必须在不同的频道上收听回复,我愿意这样做。我想要测试的是我发送的消息是否是公共频道&#39;通过“通道”接收到其他系统&#39;。
更新2: 解决Artem的问题。 谢谢Artem的建议。
是&#39; HandlerRequestConfig&#39;包含在测试配置中? - 我们无法直接调用handle()方法。相反,我想如果我发布了&#39; processRequestSubscribableChannel&#39;,则会调用HandleRequestConfig中的handle()方法,因为它会侦听同一个通道。这是错的吗?我如何测试HandleRequestConfig.handle()方法呢?
我在HandleRequestConfig的每个步骤的末尾添加了窃听(更新了代码)。我发现没有打印出窃听信息。这意味着我发布的消息甚至没有到达输入通道&#39; processRequestSubscribableChannel&#39;。我做错了什么?
注意:我尝试删除&#39; processRequestSubscribableChannel&#39; bean内部配置(以便使用applicationContext中的实际&#39; processRequestSubscribableChannel&#39;)。我得到一个不满意的依赖错误 - 预期至少1个bean配置PublishSubscribeChannel。
更新3:Artem要求发布详细信息。
@RunWith(SpringRunner.class)
@SpringBootTest
public class QueuetoQueueTest {
// Step 1 - Mocking jdbcTemplate, dataSource, entityManager so that it doesn't connect to the DB
@MockBean
@Qualifier("jdbcTemplate")
JdbcTemplate jdbcTemplate;
@MockBean
@Qualifier("dataSource")
public DataSource dataSource;
@MockBean
@Qualifier("entityManager")
public EntityManager entityManager;
@Bean(name = "ResponseChannel")
public PublishSubscribeChannel getReplyQueueChannel() {
return new PublishSubscribeChannel();
}
//Mocking the DB class
@MockBean
@Qualifier("dbStoreDaoImpl")
DBStoreDaoImpl dbStoreDaoImpl ;
//Inject the mock objects created above into the flow that stores data into the DB.
@InjectMocks
StoretoDBConfig storetoDBConfig = new StoretoDBConfig();
//Step 2 - Injecting MessageChannel used in the actual ApplicationContext
@Autowired
@Qualifier("processRequestSubscribableChannel")
MessageChannel processRequestSubscribableChannel;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
}
@Test
public void outboundtoQueueTest() {
try {
when(dbStoreDaoImpl.storeToDB(any()))
.thenReturn(1);
//create message
Message message = (Message<?>) MessageBuilder
.withPayload("Hello")
.build();
//send message - this channel is the actual channel used in ApplicationContext
processRequestSubscribableChannel.send(message);
} catch (Exception e) {
e.printStackTrace();
}
}
}
更新1:StoretoDBConfig中的代码
@Configuration
@EnableIntegration
public class StoretoDBConfig {
@Autowired
DataSource dataSource;
/*
* Below code is irrelevant to our current problem - Including for reference.
*
* storing into DB is delegated to a separate thread.
*
* @Bean
* public TaskExecutor taskExecutor() {
* return new SimpleAsyncTaskExecutor();
* }
*
* @Bean(name="executorChannelToDB")
* public ExecutorChannel outboundRequests() {
* return new ExecutorChannel(taskExecutor());
* }
* @Bean(name = "DBFailureChannel")
* public static MessageChannel getFailureChannel() {
* return new DirectChannel();
* }
* private static final Logger logger = Logger
* .getLogger(InstructionResponseHandlerOutboundtoDBConfig.class);
*/
@Bean
public IntegrationFlow handle() {
/*
* Read from 'common channel' - processRequestSubscribableChannel and send to separate thread that stores into DB.
*
/
return IntegrationFlows
.from("processRequestSubscribableChannel")
.channel("executorChannelToDB").get();
}
}
在单独的线上存入DB的代码:
@Repository
public class DBStoreDaoImpl implements DBStoreDao {
private JdbcTemplate jdbcTemplate;
@Autowired
public void setJdbcTemplate(DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
@Override
@Transactional(rollbackFor = Exception.class)
@ServiceActivator(inputChannel = "executorChannelToDB")
public void storetoDB(Message<?> msg) throws Exception {
String insertQuery ="Insert into DBTable(MESSAGE) VALUES(?)";
jdbcTemplate.update(insertQuery, msg.toString());
}
}
答案 0 :(得分:0)
请向我们展示订阅Common channel
的内容。您的图表与您向我们展示的内容无关。您演示的代码不完整。
replyChannel
真正需要向其发送消息的真正问题。如果您的流程只是单向 - 发送,存储并且没有任何东西可以返回,那么您确实无法为此获得任何内容。这就是为什么要显示这些通道适配器的原因。
观察消息历程的最佳方法是打开org.springframework.integration
类别的调试日志记录。
虽然我看到您在ContextConfiguration
中声明了这些频道,但getRequestChannel
确实没有任何订阅者。因此,没有人会消费你的信息,当然,没有人会给你回复。
请重新考虑您的测试类以使用真实的应用程序上下文。否则,如果你真的没有测试你的流程,那么完全不清楚你想要达到的目标......