Подтвердить что ты не робот

Как unit test производственные маршруты в Apache Camel?

Скажем, у меня есть маршруты, созданные в отдельном классе RouteBuilder. Это выглядит так:

  • захватить сообщение из очереди JMS
  • выполните некоторые преобразования, проверки и т.д.
  • в зависимости от результатов проверки перед конкретной JMS-очередью и сохранить что-то в БД

Я хотел бы unit test этот маршрут без брокера JMS и без БД. Я знаю, что могу издеваться над реализацией процессора, но этого недостаточно. Я не хочу менять этот маршрут (допустим, я получил этот класс в файле jar). Насколько я знаю из Camel in Action (раздел 6.2.6), чтобы иметь возможность использовать mocks конечных точек и другие вещи, мне нужно изменить определения конечных точек маршрута (в примере книги это изменение "mina: tcp://miranda" to "moker: miranda" и т.д.).

Можно ли протестировать поток в полной изоляции без изменения определений маршрутов? Если бы я получил свой RouteBuilder как отдельный класс, я вынужден как-то "скопировать" определение маршрута и изменить его вручную? Разве это не проверка неправильного?

Я новичок в Camel, и для меня было бы действительно здорово иметь изолированный unit test в то время как маршруты девектинга. Просто, чтобы иметь возможность что-то изменить, выполнить небольшой тест, наблюдать результат и т.д.

4b9b3361

Ответ 1

Предполагая, что класс RouteBuilder имеет жестко закодированные конечные точки, тогда его немного сложнее тестировать. Однако, если RouteBuilder использует заполнитель свойств для urid конечной точки, тогда вы часто сможете использовать другой набор urid для конечных точек для модульных тестов. Как объясняется в главе 6 книги Верблюда.

Если они жестко запрограммированы, вы можете использовать совет с функцией в своем unit test, как показано ниже: http://camel.apache.org/advicewith.html

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

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

В предыдущих выпусках вы можете использовать трюк interceptSendToEndpoint, который также описан в книге Camel (раздел 6.3.3)

О, вы также можете заменить компоненты макетным компонентом, как показано на стр. 169. Теперь в Camel 2.8 компонент макета больше не будет жаловаться на параметры uri, которые он не знает. Это означает, что гораздо проще заменить компоненты с помощью mocks на уровне каждого компонента.

Ответ 2

У меня

   <bean id="properties" class="org.apache.camel.component.properties.PropertiesComponent">
        <property name="location" value="classpath:shop.properties"/>
    </bean>

    <route>
        <from uri="direct://stock"/>
        <to uri="{{stock.out}}"/>
    </route>

в моем файле spring, а затем в shop.properties на пути тестового класса. У меня есть файл stock.out = xxxx, который заменяется во время выполнения, поэтому я могу использовать разные маршруты для среды выполнения и один для теста

theres лучший пример в 6.1.6 модульном тестировании в нескольких средах

Ответ 3

В то время как вы можете использовать перехваты и рекомендации по замене конечных точек в соответствии с требованиями Клауса Ибсена ответ, я думаю, что гораздо лучше разрешить вашим маршрутам принимать Endpoint чтобы ваши тесты не были связаны с вашими URI конечных точек производства.

Например, скажем, что у вас есть RouteBuilder, который выглядит примерно как

public class MyRoute extends RouteBuilder {
    @Override
    public void configure() throws Exception {
        from("http://someapi/someresource")
        .process(exchange -> {
            // Do stuff with exchange
        })
        .to("activemq:somequeue");
    }
}

Вы можете сделать так, чтобы вводить конечные точки:

public class MyRoute extends RouteBuilder {
    private Endpoint in;
    private Endpoint out;

    // This is the constructor your production code can call
    public MyRoute(CamelContext context) {
        this.in = context.getEndpoint("http://someapi/someresource");
        this.out = context.getEndpoint("activemq:somequeue");
    }

    // This is the constructor your test can call, although it would be fine
    // to use in production too
    public MyRoute(Endpoint in, Endpoint out) {
        this.in = in;
        this.out = out;
    }

    @Override
    public void configure() throws Exception {
        from(this.in)
        .process(exchange -> {
            // Do stuff with exchange
        })
        .to(this.out);
    }
}

Что можно затем протестировать следующим образом:

public class MyRouteTest {
    private Endpoint in;
    private MockEndpoint out;
    private ProducerTemplate producer;

    @Before
    public void setup() {
        CamelContext context = new DefaultCamelContext();

        this.in = context.getEndpoint("direct:in");
        this.out = context.getEndpoint("mock:direct:out", MockEndpoint.class);
        this.producer = context.createProducerTemplate();
        this.producer.setDefaultEndpoint(this.in);

        RouteBuilder myRoute = new MyRoute(this.in, this.out);
        context.addRoutes(myRoute);

        context.start();
    }

    @Test
    public void test() throws Exception {
        this.producer.sendBody("Hello, world!");
        this.out.expectedMessageCount(1);
        this.out.assertIsSatisfied();
    }
} 

Это имеет следующие преимущества:

  • ваш тест очень прост и понятен, и даже не нужно расширять CamelTestSupport или другие вспомогательные классы
  • CamelContext создается вручную, поэтому вы можете быть уверены, что создан только тестируемый маршрут.
  • Тест не заботится о URI маршрута производства
  • у вас все еще есть удобство жесткого кодирования URI конечных точек в классе маршрута, если вы хотите