我想知道是否有人可以提供帮助。我对10的首发是我对JMS和一般情况下的消息知之甚少(几乎没有) - 所以请随身携带任何答案/评论:)
鉴于这对我来说是一个学习方法,我试图整理一个非常基本的Spring JMS配置,然后编写一些集成测试来帮助我理解它是如何工作的。
这是我当前的Spring上下文配置及其JMS组件:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jms="http://www.springframework.org/schema/jms"
xmlns:amq="http://activemq.apache.org/schema/core"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/jms
http://www.springframework.org/schema/jms/spring-jms.xsd
http://activemq.apache.org/schema/core
http://activemq.apache.org/schema/core/activemq-core.xsd">
<bean class="com.lv.gi.jmstest.ApplicationContextProvider" />
<!-- Embedded ActiveMQ Broker -->
<amq:broker id="broker" useJmx="false" persistent="false">
<amq:transportConnectors>
<amq:transportConnector uri="tcp://localhost:0" />
</amq:transportConnectors>
</amq:broker>
<!-- ActiveMQ Destination -->
<amq:queue id="destination" physicalName="myQueueName" />
<!-- JMS ConnectionFactory to use, configuring the embedded broker using XML -->
<amq:connectionFactory id="jmsFactory" brokerURL="vm://localhost" />
<!-- JMS Producer Configuration -->
<bean id="jmsProducerConnectionFactory"
class="org.springframework.jms.connection.SingleConnectionFactory"
depends-on="broker"
p:targetConnectionFactory-ref="jmsFactory" />
<bean id="jmsProducerTemplate" class="org.springframework.jms.core.JmsTemplate"
p:connectionFactory-ref="jmsProducerConnectionFactory"
p:defaultDestination-ref="destination" />
<bean class="com.lv.gi.jmstest.JmsMessageProducer">
<constructor-arg index="0" ref="jmsProducerTemplate" />
</bean>
<!-- JMS Consumer Configuration -->
<bean id="jmsConsumerConnectionFactory"
class="org.springframework.jms.connection.SingleConnectionFactory"
depends-on="broker"
p:targetConnectionFactory-ref="jmsFactory" />
<jms:listener-container container-type="default"
connection-factory="jmsConsumerConnectionFactory"
acknowledge="auto">
<jms:listener destination="myQueueName" ref="jmsMessageListener" />
</jms:listener-container>
<bean id="jmsMessageListener" class="com.lv.gi.jmstest.JmsMessageListener" />
</beans>
我的JmsMessageProducer类有一个postMessage方法,如下所示:
public void postMessage(final String message) {
template.send(new MessageCreator() {
@Override
public Message createMessage(final Session session) throws JMSException {
final TextMessage textMessage = session.createTextMessage(message);
LOGGER.info("Sending message: " + message);
return textMessage;
}
});
}
我的JmsMessageListener(实现MessageListener)有一个onMessage方法,如下所示:
public void onMessage(final Message message) {
try {
if (message instanceof TextMessage) {
final TextMessage tm = (TextMessage)message;
final String msg = tm.getText();
LOGGER.info("Received message '{}'", msg);
}
} catch (final JMSException e) {
LOGGER.error(e.getMessage(), e);
}
}
在我的测试类中,我可以启动Spring上下文,获取JmsMessageProducer bean,并调用postMessage;我按预期在控制台上看到了消息:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:/com/lv/gi/jmstest/JmsMessageListenerTest-context.xml" })
public class TestJms {
private JmsMessageProducer jmsMessageProducer;
@Before
public void setup() {
jmsMessageProducer = ApplicationContextProvider.getApplicationContext().getBean(JmsMessageProducer.class);
}
@Test
public void doStuff() throws InterruptedException {
jmsMessageProducer.postMessage("message 1");
}
}
虽然这有效,但它并不是真正的测试,因为除了我在视觉上看到控制台上收到的消息之外,我无法断言已收到消息。
我们使用mockito,所以我想知道我的测试中是否有一种方法可以用模拟替换MessageListener bean,然后在其上调用verify。我想我可以通过为这些测试提供不同的Spring上下文文件来做到这一点,但这可能不适合我的下一个要求......
我的最终目标是创建一个主题,我的消息生产者可以在其中向队列发送消息,并且一个或多个MessageListener将从队列中读取消息,并且所有已注册的侦听器都已读取消息,消息将从队列中删除。 (我认为主题是正确的术语!)
为了证明这个系统能够正常工作,我想要一个可以启动Spring上下文的测试。我要做的第一件事就是用3个模拟替换监听器,所有模拟都连接到同一个目的地,这样我就可以在每个模拟器上使用验证。我发布消息,然后验证每个模拟已收到。然后我想删除/禁用2个侦听器,调用postMessage,并验证在剩下的一个模拟侦听器上调用onMessage方法。然后或许等一会儿,重新建立2个模拟,并验证他们的onMessage方法被调用。最后,检查消息是否已不在队列中(由于3个已注册的侦听器都收到了消息)
考虑到上述情况,我想我想要做的是在运行时注册和取消注册(或禁用)针对目标的侦听器,如果我能做到这一点,然后我可以注册嘲笑。
先生,这太复杂了!但我希望我能做的事情有意义吗?关于如何实现这一点的任何指针?非常感谢,
森
答案 0 :(得分:1)
在我看来,只要你进行集成测试,你就不应该试图模仿任何东西。
一方面你编写单元测试。例如,您可以通过直接从测试中调用jmsMessageListener的onMessage方法来测试使用者的行为。您通常不会使用SpringJUnit4ClassRunner进行此类测试,并且通常使用Mockito来模拟正在测试的对象的依赖关系。
另一方面,您进行了集成测试。这些是测试整个应用程序的行为。在这里使用SpringJUnit4ClassRunner.class是有意义的,但不是Mockito。你应该测试你的jmsListener应该做的事情。例如,如果您的应用程序应该写入有关传入消息的日志,请打开日志文件并进行检查。
这里的例子非常简单,也许这就是为什么你感到困惑(在我看来)。使用更复杂的侦听器,它与系统的其他部分隔离会更自然。