Search code examples
testingmockingapache-camelendpoint

Assertions not satisfied while mocking a route's endpoins, which end up calling the real ones


I have defined the following route:

from(direct(Routes.SEND_EMAIL_BOP_SINGLE_PER_USER))
    .routeId(Routes.SEND_EMAIL_BOP_SINGLE_PER_USER)
    // Split the usernames on an individual exchange each. This property is a Set<String>.
    .split(simpleF("${exchangeProperty.%s}", ExchangeProperty.USERNAMES))
        // Set the flag for the next route's processor.
        .setProperty(ExchangeProperty.SINGLE_EMAIL_PER_USER, constant(true))
        .to(direct(Routes.SEND_EMAIL_BOP))
    .end();

And written the following test:

@QuarkusTest
public class EmailRouteBuilderTest extends CamelQuarkusTestSupport {
    @Inject
    ProducerTemplate producerTemplate;

    @Override
    public String isMockEndpoints() {
        return "*";
    }

    @Test
    void testIndividualEmailPerUser() throws InterruptedException {
        final Set<String> usernames = Set.of("a", "b", "c", "d", "e");

        final Exchange exchange = this.createExchangeWithBody("");
        exchange.setProperty(ExchangeProperty.USERNAMES, usernames);

        final MockEndpoint sendEmailBopEndpoint = this.getMockEndpoint(String.format("mock:direct:%s", Routes.SEND_EMAIL_BOP), false);
        sendEmailBopEndpoint.expectedMessageCount(5);

        this.producerTemplate.send(String.format("direct:%s", Routes.SEND_EMAIL_BOP_SINGLE_PER_USER), exchange);

        sendEmailBopEndpoint.assertIsSatisfied();
    }
}

However, when I run the test, I see all sorts of error messages from the Routes.SEND_EMAIL_BOP route, which attempts to contact the real service, and the assertion fails with "expected 5 messages, 0 received". The logs indicate the following:

2023-08-31 09:51:55,896 INFO  [org.apa.cam.com.moc.InterceptSendToMockEndpointStrategy] (main) Adviced endpoint [direct://send-email-single-per-user] with mock endpoint [mock:direct:send-email-single-per-user]
2023-08-31 09:51:55,897 INFO  [org.apa.cam.com.moc.InterceptSendToMockEndpointStrategy] (main) Adviced endpoint [direct://send-email-bop] with mock endpoint [mock:direct:send-email-bop]
2023-08-31 09:51:55,896 INFO  [org.apa.cam.com.moc.InterceptSendToMockEndpointStrategy] (main) Adviced endpoint [http://boplocalhost:9999] with mock endpoint [mock:http:boplocalhost:9999]

The last line of the log corresponds to the service. I think I am understanding this whole thing wrong: I thought that mocking the endpoints made Camel not call the real services or the subsequent routes.

I have tried replacing isMockEndpoints with isMockEndpointsAndSkip but then the test doesn't work as well.

May you please help me understanding what I am doing wrong?

Thank you very much in advance.


EDIT: Updated code with "adviceWith":

@QuarkusTest
public class EmailRouteBuilderTest extends CamelQuarkusTestSupport {
    @Inject
    ProducerTemplate producerTemplate;

    @Override
    public boolean isUseAdviceWith() {
        return true;
    }

    @Test
    void testIndividualEmailPerUser() throws Exception {
        AdviceWith.adviceWith(this.context, Routes.SEND_EMAIL_BOP, a -> {
            a.mockEndpointsAndSkip("*");
        });

        final Set<String> usernames = Set.of("a", "b", "c", "d", "e");

        final Exchange exchange = this.createExchangeWithBody("");
        exchange.setProperty(ExchangeProperty.USERNAMES, usernames);

        final MockEndpoint sendEmailBopEndpoint = this.getMockEndpoint(String.format("mock:direct:%s", Routes.SEND_EMAIL_BOP), false);
        sendEmailBopEndpoint.expectedMessageCount(5);

        this.producerTemplate.send(String.format("direct:%s", Routes.SEND_EMAIL_BOP_SINGLE_PER_USER), exchange);

        sendEmailBopEndpoint.assertIsSatisfied();
    }
}

This generates the following error message:

2023-09-04 10:11:34,767 WARN  [org.apa.cam.sup.EventHelper] (main) Error notifying event 85D6EC0051F6FCF-0000000000000000 exchange completed took: 5ms. This exception will be ignored.: java.lang.NullPointerException: Cannot invoke "org.apache.camel.Endpoint.getEndpointUri()" because "endpoint" is null

And makes the test fail as well:

java.lang.AssertionError: mock://direct:send-email-bop Received message count. Expected: <5> but was: <0>
Expected :<5>
Actual   :<0>

Thanks to Vignesh's comment, I was able to make it work. Notice the route specification in the AdviceWith.adviceWith:

@QuarkusTest
public class EmailRouteBuilderTest extends CamelQuarkusTestSupport {
    @Inject
    ProducerTemplate producerTemplate;

    @Override
    public boolean isUseAdviceWith() {
        return true;
    }

    @Test
    void testIndividualEmailPerUser() throws Exception {
        AdviceWith.adviceWith(this.context, Routes.SEND_EMAIL_BOP_SINGLE_PER_USER, a -> {
            a.mockEndpointsAndSkip(String.format("direct:%s", Routes.SEND_EMAIL_BOP));
        });

        final Set<String> usernames = Set.of("a", "b", "c", "d", "e");

        final Exchange exchange = this.createExchangeWithBody("");
        exchange.setProperty(ExchangeProperty.USERNAMES, usernames);

        final MockEndpoint sendEmailBopEndpoint = this.getMockEndpoint(String.format("mock:direct:%s", Routes.SEND_EMAIL_BOP), false);
        sendEmailBopEndpoint.expectedMessageCount(5);

        this.producerTemplate.send(String.format("direct:%s", Routes.SEND_EMAIL_BOP_SINGLE_PER_USER), exchange);

        sendEmailBopEndpoint.assertIsSatisfied();
    }
}

Initially, I was trying to mock and skip a different route from the one I was testing. With this last change, I'm saying "from this route I'm testing, mock this particular endpoint", which apparently makes Apache mock the endpoint I want.

That makes the test pass!


Solution

  • Posting the comment as answer.

    "*" indicates to mock all routes. Specific route should be mocked instead. Ex: "direct:send_email_bop"