Как создать JMS-слушатель с автоматическим ответом в JUnit (в OpenEJB) - PullRequest
4 голосов
/ 16 сентября 2011

У меня есть EJB для отправки сообщения в очередь JMS и ожидания ответа от него. Я хочу протестировать EJB, легко использовать OpenEJB для выполнения теста JUnit EJB. Но проблема в том, что этот EJB будет ждать ответа JMS для продолжения процесса.

Хотя я могу отправлять сообщения в своем Junit-коде, но, поскольку EJB все еще работает, я не могу запустить его до завершения EJB.

2-е решение: я могу инициализировать MDB для прослушивания и ответа на сообщение JMS из EJB, но проблема в том, что MDB должен находиться в src \ main \ java, а не в src \ test \ java. Проблема в том, что это всего лишь тестовый код, и я не должен упаковывать его в производственную среду. (Я использую Maven)

Или я должен использовать фиктивный объект?

Ответы [ 5 ]

6 голосов
/ 16 сентября 2011

Вы на правильном пути.Есть несколько способов справиться с этим.Вот пара советов по модульному тестированию с OpenEJB и Maven.

Тестирование компонентов

Вы можете написать все виды EJB и других утилит тестирования и развернуть их.Все, что вам нужно, это ejb-jar.xml для тестового кода, например:

  • src/main/resources/ejb-jar.xml (обычный)

  • src/test/resources/ejb-jar.xml (тестируемые компоненты)

Как обычно, файл ejb-jar.xml должен содержать только <ejb-jar/> и ничего более.Его существование просто говорит OpenEJB проверять эту часть пути к классам и сканировать ее на наличие бинов.Сканирование всего пути к классам очень медленное, поэтому это просто соглашение, чтобы ускорить это.

Инъекция TestCase

С помощью вышеупомянутого src/test/resources/ejb-jar.xml вы можете очень легко добавить MDB только для тестирования и получитьон настроен для обработки запроса так, как нужно TestCase.Но src/test/resources/ejb-jar.xml также открывает некоторые другие интересные функции.

Вы можете сами TestCase сделать это, объявив ссылки на любые необходимые вам JMS-ресурсы и вставив их.

import org.apache.openejb.api.LocalClient;

@LocalClient
public class ChatBeanTest extends TestCase {

    @Resource
    private ConnectionFactory connectionFactory;

    @Resource(name = "QuestionBean")
    private Queue questionQueue;

    @Resource(name = "AnswerQueue")
    private Queue answerQueue;

    @EJB
    private MyBean myBean;


    @Override
    protected void setUp() throws Exception {
        Properties p = new Properties();
        p.put(Context.INITIAL_CONTEXT_FACTORY, "org.apache.openejb.client.LocalInitialContextFactory");
        InitialContext initialContext = new InitialContext(p);

        initialContext.bind("inject", this); // here's the magic!
    }
}

Теперь вы в одном шаге от возможности ответить на сообщение JMS самим тестовым сценарием.Вы можете запустить небольшой исполняемый модуль, который будет читать одно сообщение, отправлять нужный вам ответ, а затем завершать работу.

Может быть что-то вроде:

public void test() throws Exception {

    final Thread thread = new Thread() {
        @Override
        public void run() {
            try {
                final Connection connection = connectionFactory.createConnection();

                connection.start();

                final Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);

                final MessageConsumer incoming = session.createConsumer(requestQueue);
                final String text = ((TextMessage) incoming.receive(1000)).getText();

                final MessageProducer outgoing = session.createProducer(responseQueue);
                outgoing.send(session.createTextMessage("Hello World!"));

            } catch (JMSException e) {
                e.printStackTrace();
            }
        }
    };
    thread.setDaemon(true);
    thread.start();

    myBean.doThatThing();

    // asserts here...
}

См.

АльтернативаДескрипторы

Если вы хотите использовать решение MDB и хотите включить его только для одного теста, а не для всех тестов, вы можете определить его в специальном файле src/test/resources/mockmdb.ejb-jar.xml и включить его в конкретном тесте.случаи, когда это необходимо.

См. этот документ для получения дополнительной информации о том, как включить этот дескриптор и различные варианты альтернативных дескрипторов.

2 голосов
/ 16 сентября 2011

Если я правильно понял ваш вопрос - это плохой дизайн, когда EJB отправляет сообщение JMS, а затем ожидает ответа, что фактически противоречит всей идее EJB.

Вы отправляете сообщение JMS, а затем забываете об этом. У вас есть MDB для получения сообщения. Если EJB зависит от ответа, JMS - не тот путь, а использование другого EJB.

Чтобы проверить отправку, смоделируйте классы JMS, протестируйте MDB отдельно.

EJB предназначены для синхронных задач, JMS для асинхронных задач - если вам нужно выполнить асинхронную связь с внешней системой, я предлагаю вам спроектировать вашу систему после этого и выполнить надлежащие асинхронные потоки. EJB, который сидит и ждет ответа JMS, является в лучшем случае уродливым хаком и не добавит ничего хорошего в дизайн вашей системы.

2 голосов
/ 16 сентября 2011

Я думаю, вы должны использовать насмешки для этого. Если вы отправляете сообщения на реальный JMS-сервер, слушаете их, отвечаете на них и т. Д., То вы делаете что-то кроме модульного теста. Я не собираюсь вдаваться в спор о том, как это должно называться, но я думаю, что вполне общепризнанно, что модульный тест не должен общаться с живыми базами данных, очередями сообщений и т. Д.

1 голос
/ 17 сентября 2011

Спасибо за ответ Дэвида, это то, что я хочу.Я знаю, что юнит-тест не должен зависеть от других внешних ресурсов, таких как JMS-сервер.Но если я использую Maven + OpenEJB, я все еще могу позволить тестировать код в закрытой среде.Это может помочь в автоматическом тестировании с зависимостью от внешних ресурсов, особенно для некоторых старых программ, которые нелегко реорганизовать.

И если вы видите следующее сообщение об ошибке в initialContext.bind ("inject", this)

Убедитесь, что класс был аннотирован @ org.apache.openejb.api.LocalClient и был успешно обнаружен и развернут.

Одна ссылка - http://openejb.apache.org/3.0/local-client-injection.html,, но добавьте "openejb.tempclassloader.skip= аннотации "не работает для меня.Пожалуйста, проверьте этот документ Сбой внедрения OpenEJB Local Client .Для него уже есть патч, думаю, он будет исправлен в OpenEJB 3.1.5 или 4.0

0 голосов
/ 16 сентября 2011

Кроме того, я обнаружил, что наилучшей практикой является использование вашей логики в вашем MDB для другого класса. Это изолирует вашу бизнес-логику от нахождения в MDB и позволяет вам представить свою логику более чем одним способом (MDB, EJB, веб-сервис, POJO и т. Д.). Это также позволяет вам легче тестировать свою бизнес-логику без необходимости тестировать протокол (в данном случае JMS).

Что касается тестирования JMS, может быть лучше использовать mocking. Или, если вам действительно нужно протестировать протокол «в контейнере», посмотрите на использование чего-то вроде микроконтейнера JBoss (я полагаю, вы можете получить его в комплекте с некоторыми проектами JBoss, такими как Seam). Затем вы можете запустить мини-контейнер для тестирования таких вещей, как EJB и JMS.

Но в целом лучше избегать необходимости в контейнере, если в этом нет крайней необходимости. Вот почему отделение вашей бизнес-логики от логики реализации (даже если вы не используете фиктивные выражения) является хорошей практикой.

...