2

我想使用 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] 具有限定符 [@Default] 的类型 [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 Resource Adapter 启动:broker is EMBEDDED, connection mode is Direct Dez 23, 2012 12:上午 42:10 com.sun.messaging.jms.ra.ResourceAdapter 启动信息:MQJMSRA_RA1101:GlassFish MQ JMS 资源适配器已启动:EMBEDDED

4

2 回答 2

3

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

我的方法使用 MDB 仅捕获消息并提取底层表示(如字符串或对象)。然后将提取的消息传递给具有测试替代方案的单独 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 示例项目,我从中复制了上述代码部分。因为我对 Glassfish 不太了解,所以它使用 JBoss 作为托管容器。根据您可能使用的 JBoss 版本,您需要更改 jboss-as-arquillian-container-managed 的​​版本。

希望对某人有所帮助:-)

于 2015-05-15T07:25:02.633 回答
1

MDB 没有资格注入到其他类中。您不能将它们注入到您的测试用例中。

于 2012-12-23T12:14:04.793 回答