0

I'm new to Camel and I need to understand how to unit test my route that has two endpoints. The first endpoints gets a user ID and uses that for the second endpoint.

public RouteBuilder routeBuilder() {
    return new RouteBuilder() {
        @Override
        public void configure() throws HttpOperationFailedException {
            this.from(MyServiceConstant.ROUTE)
                    .setHeader(...)
                    .setHeader(...)
                    .to(MyConstants.THE_FIRST_ROUTE)
                    .setHeader(...)
                    .setHeader(...)
                    .process(...)
                    .setProperty(...)
                    .to(MyConstants.THE_SECOND_ROUTE)
        }
    };
}

So I have to mock both the MyConstants.THE_FIRST_ROUTE and MyConstants.THE_SECOND_ROUTE in my Test class. I did that but am not sure how to write the test. All I'm doing is hitting the second endpoint but don't know how to trigger the first.

@Produce(uri = MyServiceConstant.ROUTE)
private MyService myService;

@EndpointInject(uri = "mock:" + MyConstants.THE_FIRST_ROUTE)
private MockEndpoint mockFirstService;

@EndpointInject(uri = ""mock:" + MyConstants.THE_SECOND_ROUTE)
private MockEndpoint mockSecondService;

@Test
@DirtiesContext
public void getDetails()throws Exception {

    // **The missing part**: Is this the right way to call my first service? 
    this.mockFirstService.setUserId("123456");

    // this returns a JSON that I'll compare the service response to
    this.mockSecondService.returnReplyBody(...PATH to JSON file);

    UserDetail userDetailsInfo = this.myService.getUserDetails(...args)

    // all of my assertions
    assertEquals("First name", userDetailsInfo.getFirstName());

    MockEndpoint.assertIsSatisfied();
}
fumeng
  • 1,771
  • 5
  • 22
  • 61
  • 2
    Usually, if you work with `MockEndpoint`'s you [define certain expectations](https://camel.apache.org/components/latest/mock-component.html#_setting_expectations) and then check whether your expectations hold via [`assertIsSatisfied()`](https://camel.apache.org/components/latest/mock-component.html#_simple_example) (or one of its siblings). In case one of the routes calls an external service, such as a HTTP service, it might be beneficial to weave the route and replace the `.to(...)` with some predefined response (assuming the route invoked is not INONLY) or add a fake service to connect to – Roman Vottner Oct 10 '19 at 13:55

2 Answers2

1

Here is a link to the Unit Test cases for the Mock component. It shows how to implement tests with mock: endpoints and CamelTestSupport. @Roman Vottner is completely right in his comment.

This test case may be of specific interest to you since it shows how to swap an smtp: endpoint with a mock: endpoint. Additionally, here is official documentation on how to mock existing endpoints (To use them like test probes).

Caveat: Please bear in mind that Camel 3.0 API is quite different from Camel 2.x API, in this region. Good luck!

ShellDragon
  • 1,712
  • 2
  • 12
  • 24
  • Thank you for your help. I'm using the camel-test-spring libraries without issue. I don't want to change rewriting my test cases using CamelTestSupport. I'm able to successfully call my mocked second endpoint. I just don't know how to test my route that has 2 endpoints. – fumeng Oct 10 '19 at 16:07
  • Sorry. I missed that important `camel-test-spring` detail. However, the basic concept of setting expectations on mock endpoints and using `adviceWith` on existing routes, to attach `mock` probes stay the same. It goes like this 1. You need to define your expectations(link in Roman's comment) on the mock endpoints. 2. Hook mock endpoints into your route with `adviceWith`, intercepting MyConstants.THE_FIRST_ROUTE & MyConstants.THE_SECOND_ROUTE 3. Deliver messages to the route 4. Plain call to `MockEndpoint.assertIsSatisfied();` Unfortunately I can't find any examples to point to . – ShellDragon Oct 10 '19 at 17:00
  • I appreciate your help. Thank you very much. – fumeng Oct 10 '19 at 17:35
  • 1
    @fumeng [this thread](https://stackoverflow.com/questions/42275732/spring-boot-apache-camel-routes-testing) might contain some useful hints on how to setup and weave certain elements of your route. Especially the sample given bei `SHoko` gives a hint on how to combine `MockEndpoint`'s with route advice – Roman Vottner Oct 11 '19 at 10:37
1

I got some time today to quickly hack around some demo code, with Camel Spring boot archetype. Here we go. My route produces messages from a timer component. Explicit delivery to an endpoint is not used.

//Route Definition - myBean::saySomething() always returns String "Hello World"
@Component
public class MySpringBootRouter extends RouteBuilder {

    @Override
    public void configure() {
        from("timer:hello?period={{timer.period}}").routeId("hello_route")
            .transform().method("myBean", "saySomething")
            .to("log:foo")
                .setHeader("test_header",constant("test"))
            .to("log:bar");
    }

}

@RunWith(CamelSpringBootRunner.class)
@SpringBootTest
public class MySpringBootRouterTest {

    @Autowired
    SpringCamelContext defaultContext;

    @EndpointInject("mock:foo")
    private MockEndpoint mockFoo;
    @EndpointInject("mock:bar")
    private MockEndpoint mockBar;

    @Test
    @DirtiesContext
    public void getDetails() throws Exception {
        assertNotNull(defaultContext);
        mockBar.expectedHeaderReceived("test_header", "test");
        mockBar.expectedMinimumMessageCount(5);
        MockEndpoint.setAssertPeriod(defaultContext, 5_000L);
        MockEndpoint.assertIsSatisfied(mockFoo, mockBar);
        mockFoo.getExchanges().stream().forEach( exchange -> assertEquals(exchange.getIn().getBody(),"Hello World"));

        //This works too
        //mockBar.assertIsSatisfied();
        //mockFoo.assertIsSatisfied();
    }

    @Before
    public void attachTestProbes() throws Exception {
        //This is Camel 3.0 API with RouteReifier
        RouteReifier.adviceWith(defaultContext.getRouteDefinition("hello_route"), defaultContext, new AdviceWithRouteBuilder() {
            @Override
            public void configure() throws Exception {
           //Hook into the current route, intercept log endpoints and reroute them to mock
                interceptSendToEndpoint("log:foo").to("mock:foo");
                interceptSendToEndpoint("log:bar").to("mock:bar");
            }
        });
    }

}

Warning to visitors from future: The test case here demonstrates how to intercept log: endpoints with mock: and set expectations on them. The test case may not be testing anything worthwhile.

ShellDragon
  • 1,712
  • 2
  • 12
  • 24
  • 2
    Note that this setup will work as long as you just have one test case. In case of multiple test cases within the same context your routes would be weaved multiple times, which can be confusing if you perform certain expectations on mocks. In general it is safer to perform route-weaving only once per context. – Roman Vottner Oct 11 '19 at 17:23
  • This is fantastic - thank you very much for this example! – fumeng Oct 11 '19 at 18:50