Testing JMS driven middleware with Cucumber-JVM
I recently created sample code for testing JMS inputs and outputs using Cucumber-JVM. The full code is available on github at https://github.com/wjpowell/cucumber-jvm-jms-example. The code relies on a reusable class which I’ve set up to simplify interaction with a JMS queue, use of @BeforeClass and @AfterClass hooks for setup and teardown of test suites, and, because data loads are so often a part of testing middleware, this loads trade data from an excel sheet using the jXLS library. I can’t cover all of these features in one blog post, so for now I’m going to focus on the JMS components
The entire JMS utilities class used in the Step Definitions is included below. For convenience, this class only uses the javax.jms interfaces. This allows any connection factory to be injected, and used in the same way. The class has been structured to allow users to simply connect to a JMS server, and to create Message producers and message receivers for interacting with that server.
While most of this code is boilerplate setup and teardown of a JMS server, the createTestListener deserves some attention. This method accepts a collection as a parameter, and adds received messages to that collection. It does so by implementing an anonymous MessageListener, which can be attached to the outbound queue.
package cucumber.examples.java.jms.utilities;
public <T> MessageListener createTestListener(
final List<T> receivedCollection) {
MessageListener testListener = new MessageListener() {
@SuppressWarnings("unchecked")
@Override
public void onMessage(Message received) {
if (received instanceof ObjectMessage) {
try {
receivedCollection.add((T) ((ObjectMessage) received)
.getObject());
} catch (JMSException e) {
e.printStackTrace();
}
}
}
};
return testListener;
}
This message listener is attached to the outbound queue before any messages are sent. The code then loads the messages, and sends them through the input queue, and waits until all expected messages have been received before checking the assertions.
private void waitUntilAllOutputIsReceived(List<Trade> receivedTrades, int expectedTrades, int timeout) throws InterruptedException {
int timeoutReached = 0;
while (receivedTrades.size() != expectedTrades && timeoutReached < timeout) {
Thread.sleep(2000);
timeoutReached += 2000;
}
}
Here is the full class for the JMS utilities.
package cucumber.examples.java.jms.utilities;
public class JmsTestUtilities {
private Session session;
private Connection connection;
private ConnectionFactory connectionFactory;
public JmsTestUtilities(ConnectionFactory connectionFactory) {
this.connectionFactory = connectionFactory;
}
public Queue createQueue(String queueName) throws JMSException {
return session.createQueue(queueName);
}
public void sendMessage(Serializable object, MessageProducer producer) {
try {
// Create a messages
ObjectMessage message = session.createObjectMessage(object);
producer.send(message);
} catch (Exception e) {
System.out.println("Caught: " + e);
e.printStackTrace();
}
}
public void closeSession() throws JMSException {
session.close();
connection.close();
}
public void startServerSession() throws JMSException {
connection = connectionFactory.createConnection();
session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
connection.start();
}
public MessageProducer createInputProducer(Queue inputDestination)
throws JMSException {
MessageProducer producer = session.createProducer(inputDestination);
producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
return producer;
}
public MessageConsumer createOutputReceiver(String outputQueue)
throws JMSException {
Queue outputDestination = session.createQueue(outputQueue);
MessageConsumer outputConsumer = session
.createConsumer(outputDestination);
return outputConsumer;
}
public void attachListenerToOutputConsumer(MessageListener testListener,
MessageConsumer outputConsumer) throws JMSException {
outputConsumer.setMessageListener(testListener);
}
public <T> MessageListener createTestListener(
final List<T> receivedCollection) {
MessageListener testListener = new MessageListener() {
@SuppressWarnings("unchecked")
@Override
public void onMessage(Message received) {
if (received instanceof ObjectMessage) {
try {
receivedCollection.add((T) ((ObjectMessage) received)
.getObject());
} catch (JMSException e) {
e.printStackTrace();
}
}
}
};
return testListener;
}
public Session getSession() {
return session;
}
}