Search code examples
unit-testingapache-camel

How do i unit test the same route multiple times using Apache Camel


I am using CamelTestSupport and currently have 2 unit test for 1 routes. Both unit test is to test if exception is thrown, I used AdviceWith to replace and throw Exception.

The issue arises as written in the documentation it is recommended to only Advice the route once as it will cause the 2nd unit test to not match the route.

What can i do to reset the route after each unit test?


Solution

  • The issue arises as written in the documentation it is recommended to only Advice the route once as it will cause the 2nd unit test to not match the route.

    Where does it read like this in the documentation?

    Using AdviceWith to modify same route in different unit tests seems to work just fine. You should also be able to modify the same route in the same unit tests twice or more for as long the modifications do not conflict with each other.

    I would however avoid or at least be very careful when using AdviceWith in methods annotated with @BeforeAll or @BeforeEach as these changes will be applied for each test. Same goes for many overridable CamelTestSupport methods.

    Example

    package com.example;
    
    import org.apache.camel.RoutesBuilder;
    import org.apache.camel.builder.AdviceWith;
    import org.apache.camel.builder.RouteBuilder;
    import org.apache.camel.component.mock.MockEndpoint;
    import org.apache.camel.test.junit5.CamelTestSupport;
    import org.junit.jupiter.api.Test;
    
    public class MultiAdviceWithExampleTests extends CamelTestSupport {
    
        class ExceptionA extends Exception {}
        class ExceptionB extends Exception {}
    
        @Test
        public void exampleThrowsExceptionA() throws Exception{
    
            AdviceWith.adviceWith(context, "example", builder -> {
    
                builder.weaveByToUri("direct:replaceMe")
                    .replace()
                    .log("Throwing Exception A")
                    .throwException(new ExceptionA());
            });
    
    
            MockEndpoint exceptionAMockEndpoint = getMockEndpoint("mock:exceptionA");
            MockEndpoint exceptionBMockEndpoint = getMockEndpoint("mock:exceptionB");
            exceptionAMockEndpoint.expectedMessageCount(1);
            exceptionBMockEndpoint.expectedMessageCount(0);
    
            startCamelContext();
            template.sendBody("direct:example", null);
    
            exceptionBMockEndpoint.assertIsSatisfied();
            exceptionAMockEndpoint.assertIsSatisfied();
        }
    
        @Test
        public void exampleThrowsExceptionB() throws Exception{
    
            AdviceWith.adviceWith(context, "example", builder -> {
    
                builder.weaveByToUri("direct:replaceMe")
                    .replace()
                    .log("Throwing Exception B")
                    .throwException(new ExceptionB());
            });
    
            MockEndpoint exceptionAMockEndpoint = getMockEndpoint("mock:exceptionA");
            MockEndpoint exceptionBMockEndpoint = getMockEndpoint("mock:exceptionB");
            exceptionAMockEndpoint.expectedMessageCount(0);
            exceptionBMockEndpoint.expectedMessageCount(1);
            
            startCamelContext();
            template.sendBody("direct:example", null);
    
            exceptionAMockEndpoint.assertIsSatisfied();
            exceptionBMockEndpoint.assertIsSatisfied();
        }
    
        @Override
        protected RoutesBuilder createRouteBuilder() throws Exception {
            
            return new RouteBuilder() {
    
                @Override
                public void configure() throws Exception {
                    
                    from("direct:example")
                        .id("example")
                        .onException(ExceptionA.class)
                            .log("Caught exception A")
                            .to("mock:exceptionA")
                            .handled(true)
                        .end()
                        .onException(ExceptionB.class)
                            .log("Caught exception A")
                            .to("mock:exceptionB")
                            .handled(true)
                        .end()
                        .to("direct:replaceMe")
                    ;
                    
                    from("direct:replaceMe")
                        .routeId("replaceMe")
                        .log("should not be displayed.");
                }
                
            };
        }
    
        @Override
        public boolean isUseAdviceWith() {
            return true;
        }
    }
    

    Since overriding the isUseAdviceWith method to return true forces one to start camel context manually for each tests I am assuming that CamelTestsSupport either creates separate context and routes for each tests or at least resets the routes and mock endpoints to their original states between tests.

    Both unit test is to test if exception is thrown, I used AdviceWith to replace and throw Exception.

    If you're using JUnits assertThrows it might not work as you expect with Apache Camel as Camel will likely throw one of it's own Exceptions instead. To get the original Exception you can use template.send and get the resulting exception from the resulting exchange through .getException().getClass().

    // Remove the onException blocks from route with this 
    // or getException() will return null
    Exchange result = template.send("direct:example", new DefaultExchange(context));
    assertEquals(ExceptionB.class, result.getException().getClass());