Thursday, April 1, 2010

Unit Test with a Reusable Spring-JMS Configuration

In my previous post, I introduced a general-purpose, allegedly reusable Spring configuration for an ActiveMQ-based JMS application. In this post, I'll expand on that by writing a unit test around a basic configuration that establishes an evolving prototype.

Writing tests that fail, as it turns out, is pretty simple. Let's pick that low-hanging fruit:

package com.mybiz.jms;

import org.springframework.jms.core.JmsTemplate;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;

import javax.annotation.Resource;
import javax.jms.DeliveryMode;

@ContextConfiguration(locations =
public class BasicConfigTest extends AbstractTestNGSpringContextTests
    private JmsTemplate myTemplate;

    public void setUp() throws Exception
        System.out.println("Run BasicConfigTest...");
        assert applicationContext != null;

    public void testConfig() throws Exception
        assert myTemplate.getDeliveryMode() == DeliveryMode.PERSISTENT;
        assert myTemplate.getTimeToLive() == 10000;
        assert myTemplate.isExplicitQosEnabled();
        assert myTemplate.isPubSubDomain();
        assert myTemplate.isSessionTransacted();
        assert myTemplate.isPubSubNoLocal();

I don't need to tell you that, without any other work, this test will fail; let's take on something a bit less trivial. The test assumes a Spring configuration which resides in the same logical directory tree as the class. Here's that spring-jms-demo.xml configuration:

<beans xmlns:xsi=""     
    <import resource="spring-context.xml"/>
    <import resource="spring-jms.xml"/>


The first import establishes context-based annotationscanning for components and property placeholder
resolution, which will combine to help us reuse the generic Spring-JMS configuration (the second import). This spring-context.xml file is the beginning of my application-specific configuration:

<beans xmlns:context=""             
            <context:component-scan base-package="com.mybiz.jms"/>

That file uses a properties file ( that backfills the generic Spring-JMS configuration with more of our application specifics:

# URL for connection to broker - use testing URL:
# messages will remain in broker for 10 seconds
# 1 - non-persistent / 2 - persistent
# Specify concurrency of 40 for starters
# big perf boost, minimal risk (see comments in spring-jms.xml)
# support for flexibility on per-send basis
# concern is around a blocking consumer (see comments in spring-jms.xml)
# txn around sends
# just in case
# must specify this if it's a topic; default is false
# txn around receives
# destination for topic

Finally, I need two listeners that are referenced by the Spring-JMS configuration:

package com.mybiz.jms;

import org.springframework.stereotype.Service;

public class MyListener {}  // works for now; but this will need some work

package com.mybiz.jms;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import javax.jms.ExceptionListener;
import javax.jms.JMSException;

public class MyExceptionListener implements ExceptionListener
    private final Logger log = LoggerFactory.getLogger(getClass());
    public void onException(JMSException e)
        log.error("JMS error", e);

Now the unit test will run successfully; there's no (meaningful) output to show you, and for that matter the test and listeners are along the lines of "what's the simplest thing that would work" - it's really only done to demonstrate that all the moving parts are in place and that I've used them correctly so far. In my next, I'll start adding on some target functionality and look for ways to test it.

No comments:

Post a Comment