2014-03-27 47 views
2

我想知道是否有人可以提供幫助。我的第一個10的原因是我對JMS和消息一般知之甚少(幾乎沒有) - 所以請隨時與我聯繫,並提供任何答案/評論:)如何集成測試一些Spring 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,然後調用它來驗證。我想我可以通過爲這些測試提供不同的Spring上下文文件來實現,但這可能不適合我的下一個要求...

我的最終目標是創建一個主題,我的消息生產者可以將消息發送到隊列中,其中1個MessageListeners將從隊列中讀取消息,並且當所有註冊的偵聽器都讀取消息時,消息將從隊列中刪除。 (我認爲話題是這個正確的術語!)

爲了證明這個系統可以工作,我想要一個測試,在那裏我可以啓動Spring上下文。我想要做的第一件事是用3個連接到相同目的地的mock替換掉監聽器,這樣我就可以在每個連接上使用驗證。我會發布消息,然後確認每個模擬都已收到。然後,我想要刪除/禁用兩個監聽器,調用postMessage,並驗證onMessage方法是在剩下的一個模擬監聽器上調用的。然後或許等一會兒,然後重新建立2個mock,並驗證他們的onMessage方法被調用。最後,檢查消息不再在隊列中(由於3個已註冊的聽衆已全部收到消息)

考慮到上述情況,我想認爲我正在嘗試做什麼在運行時註冊並取消註冊(或禁用)針對目標的偵聽器,如果我可以這樣做,那麼我可以註冊mock。

Phew !,這很複雜!但我希望它對我想要做什麼有意義?

任何指針如何實現這一目標?事先非常感謝,

彌敦道

+0

OK,這篇文章告訴我如何啓動和停止監聽器: http://stackoverflow.com/questions/11407838/start-and-stop-jms-listener-using-spring 只需要找出如何現在註冊聽衆(所以我可以註冊我的嘲笑) –

回答

0

在我看來,只要你在做集成測試,你不應該試圖嘲笑什麼。

一方面你寫單元測試。例如,您可以通過直接從測試中調用jmsMessageListener的onMessage方法來測試消費者的行爲。您通常不使用SpringJUnit4ClassRunner進行此類測試,並且通常使用Mockito來模擬正在測試的對象的依賴關係。

另一方面,你有集成測試。這些正在測試整個應用程序的行爲。在這裏使用SpringJUnit4ClassRunner.class是有意義的,但不是Mockito。你應該測試一下,無論你的jmsListener應該做什麼都完成了。例如,如果您的應用程序應該寫入關於傳入消息的日誌,請打開日誌文件並檢查它。

這裏的例子很簡單,也許這就是爲什麼你感到困惑(在我看來)。對於更復雜的聽衆來說,與系統的其他部分隔離起來會更自然。

+0

感謝您的評論。也許我的術語在單元或集成測試方面是不正確的。我想我不想'測試'任何東西,因爲它沒有生產代碼。這純粹是我學習JMS的練習,而一個測試類允許我啓動Spring上下文,觸發消息並聲明它們已被接收,似乎是正確的做法。我想我稱它爲集成測試,因爲我使用的SpringJUnit4ClassRunner正如你所說的適用於集成測試。我只是想解決這些事情如何一起工作:) –

+0

@NathanRussell,好吧,我明白了。那麼也許你可以使用[spring-mockito](https://bitbucket.org/kubek2k/springockito/wiki/Home)創建一個模擬的JmsMessageListener,並用它來代替你的jmsListener。然後,您可以將其注入到您的測試中,並使用Mockito.verify,正如您通常所做的那樣。 – Alban