Version 4

    Using JBossMQ as a mock JMS implementation

     

    Motivation

     

    You want to do some jms tests inside a unit test, but you don't want to configure against an external JMS broker, i.e. you want a "mock" jms.

     

    Solution

     

    You can do this with JBossMQ which will give you a fully functional JMS implementation with the following caveats/constraints:

     

     

    Configuration

     

    First we need a configuration file that bootstraps JBossMQ using the Microcontainer with the constraints from above. Here's one:

     

    <?xml version="1.0" encoding="UTF-8"?>
    
    <deployment xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                xsi:schemaLocation="urn:jboss:bean-deployer bean-deployer_1_0.xsd"
                xmlns="urn:jboss:bean-deployer">
    
       <!-- No Persistence -->   
       <bean name="PersistenceManager" class="org.jboss.mq.pm.none.PersistenceManager"></bean>
       
       <!-- No state/durable subscriptions -->
       <bean name="StateManager" class="org.jboss.mq.sm.none.NullStateManager"></bean>
       
       <!-- Message cache -->
       <bean name="MessageCache" class="org.jboss.mq.kernel.MessageCache">
          <property name="persistenceManager"><inject bean="PersistenceManager"></inject></property>
       </bean>
       
       <!-- Desintation manager to control queues/topics -->
       <bean name="DestinationManager" class="org.jboss.mq.kernel.DestinationManager">
          <property name="persistenceManagerInstance"><inject bean="PersistenceManager"></inject></property>
          <property name="stateManagerInstance"><inject bean="StateManager"></inject></property>
          <property name="messageCacheInstance"><inject bean="MessageCache"></inject></property>
       </bean>
    
       <!-- The server -->
       <bean name="JMSServer" class="org.jboss.mq.server.JMSDestinationManager">
          <constructor factoryMethod="getInterceptor">
             <factory bean="DestinationManager"></factory>
          </constructor>
       </bean>
    
       <!-- NOTE: OTHER INTERCEPTORS COULD GO HERE -->
    
       <!-- The invoker of the interceptor chain -->
       <bean name="Invoker" class="org.jboss.mq.server.JMSServerInvoker">
          <property name="next"><inject bean="JMSServer"></inject></property>
       </bean>
    
       <!-- The in memory transport -->
       <bean name="ServerIL" class="org.jboss.mq.il.jvm.JVMServerIL">
          <constructor>
             <parameter><inject bean="Invoker"></inject></parameter>
          </constructor>
       </bean>
       
       <!-- The factory that links JMS Connection factories to transports -->
       <bean name="GCF" class="org.jboss.mq.GenericConnectionFactory">
          <constructor>
             <parameter><inject bean="ServerIL"></inject></parameter>
             <parameter>
                <map class="java.util.Properties" keyClass="java.lang.String" valueClass="java.lang.String">
                   <entry>
                      <key>ClientILService</key><value>org.jboss.mq.il.jvm.JVMClientILService</value>
                   </entry>
                </map>
             </parameter>
          </constructor>
       </bean>
       
       <!-- The JMS Connection factory -->
       <bean name="ConnectionFactory" class="org.jboss.mq.SpyConnectionFactory">
          <constructor>
             <parameter class="org.jboss.mq.GenericConnectionFactory"><inject bean="GCF"></inject></parameter>
          </constructor>
       </bean>
          
    </deployment>
    

     

    *NOTE: You could use this config to bootstrap JBossMQ using the Microcontainer generically,

    not just in a unit test!*

     

    Test Support class

     

    Next we have the support classes that bootstrap the above configuration before running the

    tests, and tears down when all the tests have been run.

     

    It also provides methods for creating conections and creating and removing destinations.

     

     

    This is the base test:

    package test;
    
    import javax.jms.Connection;
    import javax.jms.ConnectionFactory;
    
    import org.jboss.mq.SpyDestination;
    import org.jboss.mq.SpyQueue;
    import org.jboss.mq.server.JMSDestinationManager;
    import org.jboss.mq.server.JMSQueue;
    import org.jboss.test.AbstractTestDelegate;
    import org.jboss.test.kernel.junit.MicrocontainerTest;
    
    public class JBossMQMicrocontainerTest extends MicrocontainerTest
    {
       /**
        * Get the test delegate
        * 
        * @param clazz the test class
        * @return the delegate
        * @throws Exception for any error
        */
       public static AbstractTestDelegate getDelegate(Class clazz) throws Exception
       {
          return new JBossMQMicrocontainerTestDelegate(clazz);
       }
       
       /**
        * Create a new JBossMQMicrocontainer test
        * 
        * @param name the test name
        */
       public JBossMQMicrocontainerTest(String name)
       {
          super(name);
       }
       
       protected ConnectionFactory getConnectionFactory() throws Exception
       {
          return (ConnectionFactory) getBean("ConnectionFactory");
       }
       
       protected Connection createConnection() throws Exception
       {
          return getConnectionFactory().createConnection();
       }
       
       protected SpyQueue createQueue(String name) throws Exception
       {
          SpyQueue queue = new SpyQueue(name);
          JMSDestinationManager server = getJMSServer();
          JMSQueue realQueue = new JMSQueue(queue, null, server, server.getParameters());
          server.addDestination(realQueue);
          return queue;
       }
       
       protected SpyTopic createTopic(String name) throws Exception
       {
          SpyTopic queue = new SpyTopic(name);
          JMSDestinationManager server = getJMSServer();
          JMSTopic realTopic = new JMSTopic(topic, null, server, server.getParameters());
          server.addDestination(realTopic);
          return topic;
       }
       
       protected void removeDestination(SpyDestination destination) throws Exception
       {
          JMSDestinationManager server = getJMSServer();
          server.closeDestination(destination);
       }
    }
    

     

    This is the helper:

    package test;
    
    import org.jboss.test.kernel.junit.MicrocontainerTestDelegate;
    
    public class JBossMQMicrocontainerTestDelegate extends MicrocontainerTestDelegate
    {
       /**
        * Create a new JBossMQMicrocontainerTestDelegate.
        * 
        * @param clazz the class
        * @throws Exception for any error
        */
       public JBossMQMicrocontainerTestDelegate(Class clazz) throws Exception
       {
          super(clazz);
       }
    }
    

     

    An example

     

    This example shows how to use the above code to do normal JMS testing.

     

    package test;
    
    import javax.jms.Connection;
    import javax.jms.JMSException;
    import javax.jms.Message;
    import javax.jms.MessageConsumer;
    import javax.jms.MessageProducer;
    import javax.jms.Session;
    
    import junit.framework.Test;
    
    import org.jboss.mq.SpyDestination;
    
    public class ExampleUnitTestCase extends JBossMQMicrocontainerTest
    {
       public ExampleUnitTestCase(String name) throws Exception
       {
          super(name);
       }
    
       public static Test suite()
       {
          return suite(ExampleUnitTestCase.class);
       }
       
       public void testReceiveWithWaitAfterError() throws Exception
       {
          receiveAfterError(new ReceiveOperation()
          {
             public Message receive(MessageConsumer consumer) throws JMSException
             {
                return consumer.receive(1000);
             }
          });
       }
       
       public void testSomething() throws Exception
       {
          // Create the queue
          SpyDestination destination = createQueue("testQueue");
          try
          {
             // Create the connection
             Connection connection = createConnection();
             try
             {
                // Normal jms boiler plate
                Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
                MessageProducer producer = session.createProducer(destination);
                MessageConsumer consumer = session.createConsumer(destination);
                connection.start();
    
                // Send a message
                Message message = session.createMessage();
                producer.send(message);
                
                // Receive the message and assert we got it
                message = consumer.receiveNoWait();
                getLog.debug("Got message: " + message);
                assertNotNull(message);
             }
             // Always close connections in finally blocks!
             finally
             {
                connection.close();
             }
          }
          finally
          {
             // Remove the destination
             removeDestination(destination);
          }
       }
    }
    

     

    Related