【问题标题】:Arquillian, (embedded) Glassfish & JMS: How to test a worker?Arquillian,(嵌入式)Glassfish 和 JMS:如何测试工人?
【发布时间】:2012-12-10 01:32:48
【问题描述】:

我想使用 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 在注入点 [[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 开始 信息:MQJMSRA_RA1101:GlassFish MQ JMS 资源适配器启动:代理是 EMBEDDED,连接模式是 Direct Dez 23, 2012 12:42:10 AM com.sun.messaging.jms.ra.ResourceAdapter 开始 信息:MQJMSRA_RA1101:GlassFish MQ JMS 资源适配器已启动:嵌入

【问题讨论】:

    标签: testing glassfish jms jboss-arquillian


    【解决方案1】:

    测试 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 example project,我从那里复制了上面的代码部分。因为我对 Glassfish 不太了解,所以它使用 JBoss 作为托管容器。根据您可能使用的 JBoss 版本,您需要更改 jboss-as-arquillian-container-managed 的​​版本。

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

    【讨论】:

      【解决方案2】:

      MDB 不符合注入其他类的条件。您不能将它们注入到您的测试用例中。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-11-30
        • 2016-07-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多