How to mock a dynamic endpoint in Apache Camel Spring Boot

31 Views Asked by At

I want to create a unit test for a Camal route with a dynamic endpoint. To show my problem I will demonstrate on a simple example.

I started with the simple route as descibed in the Apache Camel Routes Testing in Spring Boot tutorial at Baeldung.

Route under test:

@Component
public class GreetingsFileRouter extends RouteBuilder {

    @Override
    public void configure() throws Exception {
        
        from("direct:start")
          .routeId("greetings-route")
          .setBody(constant("Hello Baeldung Readers!"))
          .to("file:output");
    }
}

and unit test:

@SpringBootTest
@CamelSpringBootTest
@MockEndpoints("file:output")
class GreetingsFileRouterUnitTest {

    @Autowired
    private ProducerTemplate template;

    @EndpointInject("mock:file:output")
    private MockEndpoint mock;

    @Test
    void whenSendBody_thenGreetingReceivedSuccessfully() throws InterruptedException {
        mock.expectedBodiesReceived("Hello Baeldung Readers!");
        template.sendBody("direct:start", null);
        mock.assertIsSatisfied();
    }
}

this works OK as expected. I extened the endpoint in the route as following:

.toD("file:output?filename=${header.fileName}");

Ie. the filename for the output file should be taken from the header filename

I have also added the header to the unit test

template.sendBodyAndHeaders("direct:start", "Hello Baeldung Readers!", Map.of("filename", "myfilename.txt"));

When I run the test the output file with filename myfilename.txt is created but the test fails with following message:

java.lang.AssertionError: mock://file:output Received message count. Expected: <1> but was: <0>
Expected :<1>
Actual   :<0>

I think it is because the file endpoint was not mocked.

I have tried many combinations for the String in @MockEndpoints and @EndpointInject like the full uri with placeholder "file:output?filename=${header.fileName}", wildcard etc. but without any success. Can anyone help.

EDIT:

After some debugging I found out that I oversimplify the problem description. In thes particular case all what has to be done is to modify @MockEndpoints("file:output") to @MockEndpoints("file:output*") or simply dropping the parameter that is "*" by default.

Unfortunate this trick does not work for my real use case. My dynamic end point looks like following:

.toD("{{api-base-url}}/projects/${header.project_id}/devices/messages/up")

where {{api-base-url}} is from application.yaml, something like https://example.com/api/v1. If use @MockEndpoints without parameters I see in the console:

Adviced endpoint [https://example.com] with mock endpoint [mock:https:example.com]

If I modify @EndpointInject to @EndpointInject("mock:https:example.com") the mock is injected as expected.

But I do not like hardcoding the generated mock name "mock:https:example.com" into the test. I can see the logic how it was probably derived from api-base-url but I would prefer to make the unit test independent on the values in application.yaml.

Is there any way i can modify the name of the generated mock endpoint name?

0

There are 0 best solutions below