Arquillian,(嵌入式)Glassfish& JMS:如何测试工人?

时间:2012-12-22 23:56:30

标签: testing glassfish jms jboss-arquillian

我想使用arquillian测试我的glassfish应用程序中包含的JMS-worker(以获得容器服务)。我的工作人员看起来如下:

package queue.worker;

import javax.ejb.ActivationConfigProperty;
import javax.ejb.MessageDriven;
import javax.jms.MessageListener;

@MessageDriven(mappedName = "java:app/jms/MailQueue", activationConfig = {
    @ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge"),
    @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue") })
public class MailWorker implements MessageListener {

public MailWorker() {
}

@Override
public void onMessage(javax.jms.Message inMessage) {
}
}

这是测试:

package queueTest.worker;

import java.io.File;

import javax.inject.Inject;

import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.junit.Arquillian;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.spec.WebArchive;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;

import queue.worker.MailWorker;

@RunWith(Arquillian.class)
public class MailWorkerTest {

@Deployment
public static WebArchive createDeployment() {
    WebArchive archive = ShrinkWrap
            .create(WebArchive.class)
            .addClasses(MailWorker.class)
            .addAsWebInfResource(new File("src/test/resources/WEB-INF/glassfish-resources.xml"),
                    "glassfish-resources.xml")
            .addAsWebInfResource(new File("src/main/webapp/WEB-INF/beans.xml"), "beans.xml");
    return archive;
}

@Inject
protected MailWorker mailWorker;

@Test
public void sendRegisterMail() {
    Assert.assertTrue(true);
}
}

执行此测试,Glassfish-JSM-Queue已启动[1],但我收到以下错误:

org.jboss.weld.exceptions.DeploymentException:WELD-001408在注入点[[field] @Inject protected queueTest.worker.MailWorkerTest.mailWorker]

当我在Mailworker.class中删除“@MessageDrivern [...]”并将其替换为“@ApplicationScoped”时,例如,一切正常 - 所以Arquillian似乎没有问题,但是JMS-相关。

如何测试JMS / Queue-Worker?

[1] Dez 23,2012 12:42:08 AM com.sun.messaging.jms.ra.ResourceAdapter start 信息:MQJMSRA_RA1101:GlassFish MQ JMS资源适配器启动:代理是EMBEDDED,连接模式是直接 Dez 23,2012 12:42:10 AM com.sun.messaging.jms.ra.ResourceAdapter start 信息:MQJMSRA_RA1101:GlassFish MQ JMS资源适配器已启动:EMBEDDED

2 个答案:

答案 0 :(得分:3)

测试MDB比测试通常的EJB和CDI bean更难,因为它们是异步执行的。即使你能够将它们注入到测试中,你也可以通过同步调用它来测试onMessage()方法。

我的方法使用MDB来捕获消息并提取底层表示(如String或Object)。然后将提取的消息传递给一个单独的CDI bean,它有一个测试备选方案。

@MessageDriven(mappedName = "jms/queue/example", activationConfig = {
        @ActivationConfigProperty(propertyName = "destinationType", 
                propertyValue = "javax.jms.Queue"),
        @ActivationConfigProperty(propertyName = "destination", 
                propertyValue = "jms/queue/example")
})
public class ExampleMDB implements MessageListener {

    @Inject
    private ExampleMessageHandler exampleMessageHandler;

    @Override
    public void onMessage(Message message) {
        if (message instanceof TextMessage) {
            TextMessage textMessage = (TextMessage) message;
            try {
                exampleMessageHandler.doSomething(textMessage.getText());
            } catch (JMSException e) {
                throw new RuntimeException("That was unexpected!", e);
            }
        }
    }
}

ExampleMessageHandler定义了doSomething(String text)。

对于测试范围,我们需要一个实现来捕获传递给doSomething()的参数,并使它们可以被测试类访问。您可以通过以下实现来实现此目的:

@Alternative
@ApplicationScoped
public class ExampleMessageHandlerTestable implements ExampleMessageHandler {

    private BlockingQueue<String> queue = new LinkedBlockingQueue<String>();


    public void doSomething(String text) {
        queue.add(text);
    }

    public String poll(int secondsUntilInterrupt) throws InterruptedException {
        return queue.poll(secondsUntilInterrupt, TimeUnit.SECONDS);
    }

}

这是生产代码使用的实际实现的CDI替代方案。现在让Arquillian测试使用这个替代方案。这是测试类:

@RunWith(Arquillian.class)
public class ExampleMDBGoodTest {

    @Resource(mappedName = "ConnectionFactory", name = "ConnectionFactory")
    private ConnectionFactory connectionFactory;

    @Resource(mappedName = "jms/queue/example", name = "jms/queue/example")
    private Queue queue;

    @Inject
    private ExampleMessageHandler exampleMessageHandler;

    @Deployment
    public static WebArchive createDeployment() {
        WebArchive archive = ShrinkWrap.create(WebArchive.class, "exampleMDB.war")
                .addPackages(true, ExampleMDB.class.getPackage())
                .addAsWebInfResource("hornetq-jms.xml", "hornetq-jms.xml")
                .addAsWebInfResource("beans-alternative.xml", "beans.xml");
        System.out.println(archive.toString(true));
        return archive;
    }

    @Test
    public void testOnMessage() throws Exception {
        Connection connection = connectionFactory.createConnection();
        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
        MessageProducer producer = session.createProducer(queue);

        TextMessage textMessage = session.createTextMessage("Hello world!");
        producer.send(textMessage);
        session.close();
        connection.close();

        // We cast to our configured handler defined in beans.xml
        ExampleMessageHandlerTestable testHandler = 
                (ExampleMessageHandlerTestable) exampleMessageHandler;
        assertThat(testHandler.poll(10), is("Hello world!"));
    }

}

一些解释在这里发生了什么:测试请求JMS ConnectionFactory和MDB侦听的队列。这些创建了受测试的MDB使用的JMS消息。然后我们创建一个测试部署。 hornetq-jms.xml为测试定义了一个特殊队列。通过包含beans-alternative.xml,我们确保MDB使用我们的测试替代方案。

<beans xmlns="http://java.sun.com/xml/ns/javaee" 
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="
http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">

    <alternatives>
        <class>com.github.mcs.arquillian.mdb.example.ExampleMessageHandlerTestable</class>
    </alternatives>

</beans>

测试用例本身应该是直截了当的。将新的JMS消息发送到队列。然后我们等待最多10秒钟,在我们的测试选项中添加新消息。通过使用阻塞队列,我们​​可以定义超时,在此之后测试失败。但是一旦MDB调用替代bean,测试本身就立即完成。

我已从我复制上述代码部分的位置上传了一个小Maven example project。因为我对Glassfish了解不多,所以它使用JBoss作为托管容器。根据您可能使用的JBoss版本,您需要更改jboss-as-arquillian-container-managed的版本。

希望能帮到某人: - )

答案 1 :(得分:1)

MDB不符合注入其他类的资格。你不能将它们注入你的测试用例。