testing - Arquillian,(嵌入式)Glassfish 和 JMS : How to test a worker?

标签 testing glassfish jms jboss-arquillian

我想使用 arquillian 测试包含在 glassfish 应用程序中的 JMS-worker(以拥有容器服务)。我的 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 类型 [MailWorker] 与注入(inject)点 [[field] @Inject protected queueTest.worker.MailWorkerTest.mailWorker] 处带有限定符 [@Default] 的依赖关系不满足

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

如何测试 JMS/Queue-Worker?

[1] 2012 年 23 月 12:42:08 上午 com.sun.messaging.jms.ra.ResourceAdapter 启动 信息:MQJMSRA_RA1101:GlassFish MQ JMS 资源适配器启动:代理已嵌入,连接模式为直接 2012 年 23 月 12:42:10 上午 com.sun.messaging.jms.ra.ResourceAdapter 启动 信息:MQJMSRA_RA1101:GlassFish MQ JMS 资源适配器已启动:EMBEDDED

最佳答案

测试 MDB 比测试通常的 EJB 和 CDI bean 更困难,因为它们是异步执行的。即使您能够将它们注入(inject)到您的测试中,您也可以通过同步调用 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 example project从我复制上述代码部分的地方。因为我对Glassfish了解不多,所以它使用JBoss作为托管容器。根据您可能使用的 JBoss 版本,您需要更改 jboss-as-arquillian-container-management 的版本。

希望对某人有帮助:-)

关于testing - Arquillian,(嵌入式)Glassfish 和 JMS : How to test a worker?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14007600/

相关文章:

android - Mockito Uri.parse 总是返回 null

jakarta-ee - Eclipse 构建路径警告

java - 使用 RabbitMQ 和 JMS API 进行事务管理

shell - KornShell (ksh) 中的测试命令

python - 测试我已连接到 Django 中的特定信号

Eclipse:Glassfish 和 Tomcat 不工作

ssl - 如何将 letsencrypt 免费 ssl 安装到 glassfish 4.x 服务器

java - 通过 MOM 在 WAS 集群内传播配置

java - JMS 与 akka 和多线程

forms - 我无法从导入了 FormsModule、ReactiveFormsModule 的 TestBed 获取 FormBuilder