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?