Search code examples
javaapache-camel

Get body in unit test camel


I am trying to perform a unit test for one of my routes in camel however I can't find a way to check the body I receive from my route and check if it is what is expected. How can I do this with or without mocks?

Route

@Component
public class MyRoute extends RouteBuilder {    

    @Override public void configure() throws Exception {        
        from("direct:MyRoute")                
        .routeId("MyRoute")                
        .marshal().json(JsonLibrary.Jackson)                
        .log("Marshal to \n${body}");    
    }
}

Test

public class MyRouteTest extends CamelTestSupport {    
    @Override 
    protected RouteBuilder createRouteBuilder() throws Exception {    
        return new MyRoute();    
    }    

    @Test
    public void testRoute() throws Exception {
        NotifyBuilder notify = new NotifyBuilder(context).whenDone(1).create();        
        Map<String,Object> map = new LinkedHashMap<>();        
        map.put("name","your_name"); 
        template.sendBody("direct:MyRoute", map);     
        assertTrue(notify.matchesWaitTime());
   }
}

Solution

  • With mocks

    You can use AdviceWith and weaveAddLast to add for example mock:result to end of a route. Then use the injected MockEndpoint to define assertions for the exchange. MockEndpoint comes with many handy methods that you can use to check validity of the exchange.

    When using AdviceWith to modify routes for tests, remember to use the @UseAdviceWith annotation and start the CamelContext manually before each test. This is to avoid unnecessary restarts of adviced routes.

    package com.example;
    
    import org.apache.camel.CamelContext;
    import org.apache.camel.EndpointInject;
    import org.apache.camel.ProducerTemplate;
    import org.apache.camel.builder.AdviceWith;
    import org.apache.camel.component.mock.MockEndpoint;
    import org.apache.camel.test.spring.junit5.CamelSpringBootTest;
    import org.apache.camel.test.spring.junit5.UseAdviceWith;
    import org.junit.jupiter.api.Test;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.context.SpringBootTest;
    
    @SpringBootTest
    @CamelSpringBootTest
    @UseAdviceWith
    public class MySpringBootApplicationTest  {
    
        @Autowired
        private CamelContext camelContext;
    
        @Autowired
        private ProducerTemplate producerTemplate;
    
        @EndpointInject(uri = "mock:result")
        private MockEndpoint resulMockEndpoint;
    
        @Test
        public void test() throws Exception {
            
            resulMockEndpoint.expectedMessageCount(1);
            resulMockEndpoint.message(0)
                .body().isEqualTo("Hello world");
    
            addMockEndpointAsLast("hello");
    
            camelContext.start();
            producerTemplate.sendBody("direct:hello", "world");
    
            resulMockEndpoint.assertIsSatisfied();
        }
    
        MockEndpoint addMockEndpointAsLast(String routeId) throws Exception {
    
            AdviceWith.adviceWith(camelContext, routeId, builder -> {
                builder.weaveAddLast()
                    .to("mock:result")
                ;
            });
            return resulMockEndpoint;
        }
    }
    

    If you want to further examine the exchange, you can get it from the exchanges list of MockEndpoint. Below is example on how to get body of first exchange as String.

    String result = resulMockEndpoint.getExchanges().get(0)
        .getMessage().getBody(String.class);
    

    Without mocks

    You can use ProducerTemplate.send method which returns the resulting exchange. However instead of body of any type the method wants you to provide it with exchange object which you can create using DefaultExchange class.

    package com.example;
    
    import static org.junit.jupiter.api.Assertions.assertEquals;
    
    import org.apache.camel.CamelContext;
    import org.apache.camel.Exchange;
    import org.apache.camel.ProducerTemplate;
    import org.apache.camel.support.DefaultExchange;
    import org.apache.camel.test.spring.junit5.CamelSpringBootTest;
    import org.junit.jupiter.api.Test;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.context.SpringBootTest;
    
    @SpringBootTest
    @CamelSpringBootTest
    public class MySpringBootApplicationTest  {
    
        @Autowired
        private CamelContext camelContext;
    
        @Autowired
        private ProducerTemplate producerTemplate;
    
        @Test
        void testWithoutMock(){
    
            Exchange exchange = new DefaultExchange(camelContext);
            exchange.getMessage().setBody("world");
    
            Exchange resultExchange = producerTemplate.send("direct:hello", exchange);
            assertEquals("Hello world", resultExchange.getMessage().getBody());
        }
    }
    

    RouteBuilder

    package com.example;
    
    import org.apache.camel.builder.RouteBuilder;
    import org.springframework.stereotype.Component;
    
    @Component
    public class MySpringBootRouter extends RouteBuilder {
    
        @Override
        public void configure() {
    
            from("direct:hello")
                .routeId("hello")
                .setBody().simple("Hello ${body}")
                .log("${body}")
            ;
        }
    }
    

    Examples use Apache Camel version 3.20.2