2

arquillianを使用してGlassfishアプリケーションに含まれているJMSワーカーをテストしたいと思います(container-servicesを使用するため)。私の労働者は次のように見えます:

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リソースアダプターの開始:ブローカーはEMBEDDED、接続モードはDirect Dez 23、2012 12: 42:10 AM com.sun.messaging.jms.ra.ResourceAdapter開始情報:MQJMSRA_RA1101:GlassFish MQ JMSリソースアダプターが開始されました:EMBEDDED

4

2 に答える 2

3

MDBのテストは、非同期で実行されるため、通常のEJBおよびCDIBeanのテストよりも困難です。それらをテストに挿入できたとしても、onMessage()メソッドを同期的に呼び出すことでテストできます。

私のアプローチでは、MDBを使用してメッセージのみをキャッチし、基になるプレゼンテーション(文字列やオブジェクトなど)を抽出します。次に、抽出されたメッセージを、代替テストがある別のCDIBeanに渡します。

@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!"));
    }

}

ここで何が起こっているのかについての説明:テストは、JMSConnectionFactoryと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 に答える