19

I've got a series of "pipelined" components that all communicate through ActiveMQ message queues. Each component uses Camel to treat each of these queues as an Endpoint. Each component uses the same basic pattern:

Basic component pattern

Where each component consumes messages off of an input queue, processes the message(s), and then places 1+ messages on an outbound/output queue. The "output" queue then becomes the "input" queue for the next component in the chain. Pretty basic.

I am now trying to roll up my sleeves and provide unit testing for each component using the MockEndpoints provided by Camel's test API. I have been pouring over the javadocs and the few examples on Camel's website, but am having difficulty connecting all the dots.

It seems to me that, for each component, a portion of my unit testing is going to want to accomplish the following three things:

  • Test to see if there are messages waiting on a particular "input" queue
  • Pull those messages down and process them
  • Push new messages to an "output" queue and verify that they made it there

I believe I need to create MockEndpoints for each queue like so:

@EndpointInject(uri = "mock:inputQueue")
protected MockEndpoint intputQueue;

@EndpointInject(uri = "mock:outputQueue")
protected MockEndpoint outputQueue;

So now, in my JUnit test methods, I can set up expectations and interact with these endpoints:

@Test
public final void processMethodShouldSendToOutputQueue()
{
    Component comp = new Component();
    comp.process();

    outputQueue.assertIsSatisfied();
}

I'm just not understanding how to wire everything up correctly:

  • How do I connect comp to the inputQueue and outputQueue MockEndpoints?
  • For each MockEndpoint, how do I set up expectations so that assertIsSatisfied() checks that a message is present inside a particular queue, or that a particular queue contains messages?
Aleksandr Kravets
  • 5,750
  • 7
  • 53
  • 72
IAmYourFaja
  • 55,468
  • 181
  • 466
  • 756

1 Answers1

12

Adam, there are several ways to do this.

For POJO components, blackbox test them separately from any Camel context/routing to focus on business logic.

If you want to do end-to-end testing of the routes, consider using one of these approaches to validate that each step in the route is satisfied.

  • use NotifyBuilder to build Exchange validation expressions (somewhat complex to get your head around)
  • use AdviceWith to dynamically change the route before its run (add Log/Mock endpoints, etc)

I prefer AdviceWith because its very flexible and leverages the familiar MockEndpoints. For a complete example of this, see this unit test

In short, you will create a unit test to inject MockEndpoints into your route and then validate against them as usual...

context.getRouteDefinition("myRouteId").adviceWith(context, new AdviceWithRouteBuilder() {
    @Override
    public void configure() throws Exception {
        // mock all endpoints
        mockEndpoints();
    }
});

getMockEndpoint("mock:direct:start").expectedBodiesReceived("Hello World");

template.sendBody("direct:start", "Hello World");
Ben ODay
  • 20,784
  • 9
  • 45
  • 68
  • I appreciate the answer boday - and yes I will be testing the components separately (and their "process" methods). However, as part of a sort of "integration test" between the components and their input/output queues, I do want to automate the verficiation of messages moving a long defined routes. The AdviceWith API seems interesting and I'll check it out. But its existence seems to nullify the need for a MockEndpoint. Can you clarify when it is appropriate to use each? And thanks again! – IAmYourFaja Dec 20 '11 at 20:11
  • Adam, for true end-to-end testing, use AdviceWith to inject MockEndpoints dynamically into you existing production routes. Mock is very powerful because of the stats/assertion APIs that are provided, but should NOT be added to production routes directly. I'll update my answer with an example of doing this... – Ben ODay Dec 21 '11 at 05:43
  • @boday, can you please complete you example showing how to send an `Exchange` to the route ? I ask that because it is not clear to me how you can send an `Exchange` to the route's `from`. Thanks in advance. – danidemi Jan 11 '16 at 16:13
  • sure...I updated example to include the template.sendBody() call...see the referenced unit test for a full example... – Ben ODay Jan 11 '16 at 20:09