Тестирование весенних загрузок Apache Camel Routes

У меня есть приложение Springboot, в котором настроены верблюжьи маршруты.

public class CamelConfig {
private static final Logger LOG = LoggerFactory.getLogger(CamelConfig.class);

@Value("${activemq.broker.url:tcp://localhost:61616}")
String brokerUrl;

@Value("${activemq.broker.maxconnections:1}")
int maxConnections;

@Bean
ConnectionFactory jmsConnectionFactory() {
    PooledConnectionFactory pooledConnectionFactory = new PooledConnectionFactory(new ActiveMQConnectionFactory(brokerUrl));
    pooledConnectionFactory.setMaxConnections(maxConnections);
    return pooledConnectionFactory;
}

@Bean
public RoutesBuilder route() {
    LOG.info("Initializing camel routes......................");
    return new SpringRouteBuilder() {
        @Override
        public void configure() throws Exception {
            from("activemq:testQueue").to("bean:queueEventHandler?method=handleQueueEvent");
             }
    };
}

}

Я хочу проверить этот маршрут от activemq:testQueue к queueEventHandler::handleQueueEvent
Я пробовал разные вещи, упомянутые здесь http://camel.apache.org/camel-test.html, но, похоже, это не работает.

Я пытаюсь сделать что-то подобное

@RunWith(SpringRunner.class)
@SpringBootTest(classes = {CamelConfig.class,   CamelTestContextBootstrapper.class})
public class CamelRouteConfigTest {

@Produce(uri = "activemq:testQueue")
protected ProducerTemplate template;

@Test
public void testSendMatchingMessage() throws Exception {
    template.sendBodyAndHeader("testJson", "foo", "bar");
    .....
    ..... verify handleQueueEvent method is called on bean queueEventHandler by mocking

}

Но мой ProducerTemplate всегда нулевой. Я попробовал Autowiring Camelcontext, для которого я получил исключение, сказав, что он не может разрешить camelContext. Но это можно решить, добавив SpringCamelContext.class в классы @SpringBootTest. Но мой ProducerTemplate все еще нулевой.

пожалуйста, предложите. Я использую Camel 2.18 Springboot 1.4

3 ответа

Решение

Вот как я это сделал наконец

@RunWith(SpringRunner.class)
public class CamelRouteConfigTest extends CamelTestSupport {

    private static final Logger LOG = LoggerFactory.getLogger(CamelRouteConfigTest.class);
    private static BrokerService brokerSvc = new BrokerService();

    @Mock
    private QueueEventHandler queueEventHandler;

    @BeforeClass
    //Sets up a embedded broker.
    public static void setUpBroker() throws Exception {
        brokerSvc.setBrokerName("TestBroker");
        brokerSvc.addConnector("tcp://localhost:61616");
        brokerSvc.setPersistent(false);
        brokerSvc.setUseJmx(false);
        brokerSvc.start();
    }

    @Override
    protected RoutesBuilder createRouteBuilder() throws Exception {
        return new CamelConfig().route();
    }

    // properties in .yml has to be loaded manually. Not sure of .properties file
    @Override
    protected Properties useOverridePropertiesWithPropertiesComponent() {
        YamlPropertySourceLoader loader = new YamlPropertySourceLoader();
        try {
            PropertySource<?> applicationYamlPropertySource = loader.load(
                "properties", new ClassPathResource("application.yml"),null);// null indicated common properties for all profiles.
            Map source = ((MapPropertySource) applicationYamlPropertySource).getSource();
            Properties properties = new Properties();
            properties.putAll(source);
            return properties;
        } catch (IOException e) {
            LOG.error("application.yml file cannot be found.");
        }

        return null;
    }

    @Override
    protected JndiRegistry createRegistry() throws Exception {
        JndiRegistry jndi = super.createRegistry();
        MockitoAnnotations.initMocks(this);
        jndi.bind("queueEventHandler", queueEventHandler);

        return jndi;
    }

    @Test
    // Sleeping for a few seconds is necessary, because this line template.sendBody runs in a different thread and
    // CamelTest takes a few seconds to do the routing.
    public void testRoute() throws InterruptedException {
        template.sendBody("activemq:productpushevent", "HelloWorld!");
        Thread.sleep(2000);
        verify(queueEventHandler, times(1)).handleQueueEvent(any());
    }

    @AfterClass
    public static void shutDownBroker() throws Exception {
        brokerSvc.stop();
    }
}

В Camel 2.22.0 и более поздних версиях, поддерживающих Spring Boot 2, вы можете использовать следующий шаблон для проверки ваших маршрутов с поддержкой Spring Boot 2:

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.NONE, classes = {
    Route1.class,
    Route2.class,
    ...
})
@EnableAutoConfiguration
@DisableJmx
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS)
public class RouteTest {

  @TestConfiguration
  static class Config {
    @Bean
    CamelContextConfiguration contextConfiguration() {
      return new CamelContextConfiguration() {
        @Override
        public void beforeApplicationStart(CamelContext camelContext) {
          // configure Camel here
        }

        @Override
        public void afterApplicationStart(CamelContext camelContext) {
          // Start your manual routes here
        }
      };
    }

    @Bean
    RouteBuilder routeBuilder() {
      return new RouteBuilder() {
        @Override
        public void configure() {
          from("direct:someEndpoint").to("mock:done");
        }
      };
    }

    // further beans ...
  }

  @Produce(uri = "direct:start")
  private ProducerTemplate template;
  @EndpointInject(uri = "mock:done")
  private MockEndpoint mockDone;

  @Test
  public void testCamelRoute() throws Exception {
    mockDone.expectedMessageCount(1);

    Map<String, Object> headers = new HashMap<>();
    ...
    template.sendBodyAndHeaders("test", headers);

    mockDone.assertIsSatisfied();
  }
}

Spring Boot различает @Configuration а также @TestConfiguration, Учебник для начинающих заменит любую существующую конфигурацию, если она аннотирована классом верхнего уровня, а @TestConfiguration будет запущен в дополнение к другим конфигурациям.

Кроме того, в более крупных проектах вы можете столкнуться с проблемами автоконфигурации, поскольку вы не можете полагаться на Spring Boot 2 для настройки настраиваемого пула базы данных или чего-то не так, или в случаях, когда у вас есть определенная структура каталогов и конфигурации не находятся в каталог прямого предка. В этом случае, вероятно, предпочтительнее опустить @EnableAutoConfiguration аннотаций. Чтобы сказать Spring, чтобы он все еще автоматически настраивал Camel, вы можете просто передать CamelAutoConfiguration.class к классам, упомянутым в @SpringBootTest

@SpringBootTest(webEnvironment = WebEnvironment.NONE, classes = {
    Route1.class,
    Route2.class,
    RouteTest.Config.class,
    CamelAutoConfiguration.class
}

Поскольку автоматическая конфигурация не выполняется, Spring не будет загружать тестовую конфигурацию внутри вашего тестового класса и инициализировать Camel. Добавив эти конфиги в загрузочные классы вручную, Spring сделает это за вас.

Для одного маршрута с MQ и Spring Boot вот так:

    @Component
    public class InboundRoute extends RouteBuilder {
    
      @Override
      public void configure() {
        JaxbDataFormat personDataFormat = new JaxbDataFormat();
        personDataFormat.setContextPath(Person.class.getPackage().getName());
        personDataFormat.setPrettyPrint(true);
        from("direct:start").id("InboundRoute")
            .log("inbound route")
            .marshal(personDataFormat)
            .to("log:com.company.app?showAll=true&multiline=true")
            .convertBodyTo(String.class)
            .inOnly("mq:q.empi.deim.in")
            .transform(constant("DONE"));
      }
    }

Я использую adviceWith, чтобы заменить конечную точку и использовать только макеты:

    @RunWith(CamelSpringBootRunner.class)
    @UseAdviceWith
    @SpringBootTest(classes = InboundApp.class)
    @MockEndpoints("mock:a")
    public class InboundRouteCamelTest {
    
      @EndpointInject(uri = "mock:a")
      private MockEndpoint mock;
    
      @Produce(uri = "direct:start")
      private ProducerTemplate template;
    
      @Autowired
      private CamelContext context;
    
      @Test
      public void whenInboundRouteIsCalled_thenSuccess() throws Exception {
        mock.expectedMinimumMessageCount(1);
        RouteDefinition route = context.getRouteDefinition("InboundRoute");
        route.adviceWith(context, new AdviceWithRouteBuilder() {
          @Override
          public void configure() {
            weaveByToUri("mq:q.empi.deim.in").replace().to("mock:a");
          }
        });
        context.start();
    
        String response = (String) template.requestBodyAndHeader("direct:start",
            getSampleMessage("/SimplePatient.xml"), Exchange.CONTENT_TYPE, MediaType.APPLICATION_XML);
    
        assertThat(response).isEqualTo("DONE");
        mock.assertIsSatisfied();
      }
    
      private String getSampleMessage(String filename) throws Exception {
        return IOUtils
            .toString(this.getClass().getResourceAsStream(filename), StandardCharsets.UTF_8.name());
      }
    }

Я использую следующие зависимости: Spring Boot 2.1.4-RELEASE и Camel 2.23.2. Полный исходный код доступен на Github.

Вы пробовали использовать тестер Camel?

@RunWith(CamelSpringJUnit4ClassRunner.class)

Если вы используете camel-spring-boot зависимость, вы можете знать, что он использует автоматическую настройку для настройки Camel:

CamelAutoConfiguration.java

Это означает, что вам также может понадобиться добавить @EnableAutoConfiguration к вашему тесту.

Другие вопросы по тегам