THIS IS A TEST INSTANCE. ALL YOUR CHANGES WILL BE LOST!!!!
Wiki Markup |
---|
h2. Mock Component
{include:Testing Summary Include}
The Mock component provides a powerful declarative testing mechanism, which is similar to [jMock|http://jmock.org] in that it allows declarative expectations to be created on any Mock endpoint before a test begins. Then the test is run, which typically fires messages to one or more endpoints, and finally the expectations can be asserted in a test case to ensure the system worked as expected.
This allows you to test various things like:
* The correct number of messages are received on each endpoint,
* The correct payloads are received, in the right order,
* Messages arrive on an endpoint in order, using some [Expression] to create an order testing function,
* Messages arrive match some kind of [Predicate] such as that specific headers have certain values, or that parts of the messages match some predicate, such as by evaluating an [XPath] or [XQuery] [Expression].
*Note* that there is also the [Test endpoint|Test] which is a Mock endpoint, but which uses a second endpoint to provide the list of expected message bodies and automatically sets up the Mock endpoint assertions. In other words, it's a Mock endpoint that automatically sets up its assertions from some sample messages in a [File] or [database|JPA], for example.
h3. URI format
{code}
mock:someName[?options]
{code}
Where *someName* can be any string that uniquely identifies the endpoint.
You can append query options to the URI in the following format, {{?option=value&option=value&...}}
h3. Options
{div:class=confluenceTableSmall}
|| Option || Default || Description ||
| {{reportGroup}} | {{null}} | A size to use a [throughput logger|Log] for reporting |
{div}
h3. Simple Example
Here's a simple example of Mock endpoint in use. First, the endpoint is resolved on the context. Then we set an expectation, and then, after the test has run, we assert that our expectations have been met.
{code}
MockEndpoint resultEndpoint = context.resolveEndpoint("mock:foo", MockEndpoint.class);
resultEndpoint.expectedMessageCount(2);
// send some messages
...
// now lets assert that the mock:foo endpoint received 2 messages
resultEndpoint.assertIsSatisfied();
{code}
You typically always call the [assertIsSatisfied() method|http://camel.apache.org/maven/current/camel-core/apidocs/org/apache/camel/component/mock/MockEndpoint.html#assertIsSatisfied()] to test that the expectations were met after running a test.
Camel will by default wait 20 seconds when the {{assertIsSatisfied()}} is invoked. This can be configured by setting the {{setResultWaitTime(millis)}} method.
h3. Setting expectations
You can see from the javadoc of [MockEndpoint|httphttp://camel.apache.org/maven/current/camel-core/apidocs/org/apache/camel/component/mock/MockEndpoint.html] the various helper methods you can use to set expectations. The main methods are as follows:
{div:class=confluenceTableSmall}
|| Method || Description ||
| [expectedMessageCount(int)|http://camel.apache.org/maven/current/camel-core/apidocs/org/apache/camel/component/mock/MockEndpoint.html#expectedMessageCount(int)] | To define the expected message count on the endpoint. |
| [expectedMinimumMessageCount(int)|http://camel.apache.org/maven/current/camel-core/apidocs/org/apache/camel/component/mock/MockEndpoint.html#expectedMinimumMessageCount(int)] | To define the minimum number of expected messages on the endpoint. |
| [expectedBodiesReceived(...)|http://camel.apache.org/maven/current/camel-core/apidocs/org/apache/camel/component/mock/MockEndpoint.html#expectedBodiesReceived(java.lang.Object...)] | To define the expected bodies that should be received (in order). |
| [expectedHeaderReceived(...)|http://camel.apache.org/maven/current/camel-core/apidocs/org/apache/camel/component/mock/MockEndpoint.html#expectedHeaderReceived(java.lang.String,%20java.lang.String)] | To define the expected header that should be received |
| [expectsAscending(Expression)|http://camel.apache.org/maven/current/camel-core/apidocs/org/apache/camel/component/mock/MockEndpoint.html#expectsAscending(org.apache.camel.Expression)] | To add an expectation that messages are received in order, using the given [Expression] to compare messages. |
| [expectsDescending(Expression)|http://camel.apache.org/maven/current/camel-core/apidocs/org/apache/camel/component/mock/MockEndpoint.html#expectsDescending(org.apache.camel.Expression)] | To add an expectation that messages are received in order, using the given [Expression] to compare messages. |
| [expectsNoDuplicates(Expression)|http://camel.apache.org/maven/current/camel-core/apidocs/org/apache/camel/component/mock/MockEndpoint.html#expectsNoDuplicates(org.apache.camel.Expression)] | To add an expectation that no duplicate messages are received; using an [Expression] to calculate a unique identifier for each message. This could be something like the {{JMSMessageID}} if using JMS, or some unique reference number within the message. |
{div}
Here's another example:
{code}
resultEndpoint.expectedBodiesReceived("firstMessageBody", "secondMessageBody", "thirdMessageBody");
{code}
h4. Adding expectations to specific messages
In addition, you can use the [message(int messageIndex)|http://camel.apache.org/maven/current/camel-core/apidocs/org/apache/camel/component/mock/MockEndpoint.html#message(int)] method to add assertions about a specific message that is received.
For example, to add expectations of the headers or body of the first message (using zero-based indexing like {{java.util.List}}), you can use the following code:
{code}
resultEndpoint.message(0).header("foo").isEqualTo("bar");
{code}
There are some examples of the Mock endpoint in use in the [camel-core processor tests|http://svn.apache.org/viewvc/camel/trunk/camel-core/src/test/java/org/apache/camel/processor/].
h3. Mocking existing endpoints
*Available as of Camel 2.7*
Camel now allows you to automatic mock existing endpoints in your Camel routes. Suppose you have the given route below:
{snippet:id=route|title=Route|lang=java|url=camel/trunk/camel-core/src/test/java/org/apache/camel/processor/interceptor/AdviceWithMockEndpointsTest.java}
You can then use the {{adviceWith}} feature in Camel to mock all the endpoints in a given route from your unit test, as shown below:
{snippet:id=e1|title=adviceWith mocking all endpoints|lang=java|url=camel/trunk/camel-core/src/test/java/org/apache/camel/processor/interceptor/AdviceWithMockEndpointsTest.java}
Notice that the mock endpoints is given the uri {{mock:<endpoint>}}, for example {{mock:direct:foo}}. Camel logs at {{INFO}} level the endpoints being mocked:
{code}
INFO Adviced endpoint [direct://foo] with mock endpoint [mock:direct:foo]
{code}
Its also possible to only mock certain endpoints using a pattern. For example to mock all {{log}} endpoints you do as shown:
{snippet:id=e2|lang=java|title=adviceWith mocking only log endpoints using a pattern|url=camel/trunk/camel-core/src/test/java/org/apache/camel/processor/interceptor/AdviceWithMockEndpointsTest.java}
The pattern supported can be a wildcard or a regular expression. See more details about this at [Intercept] as its the same matching function used by Camel.
{info}
Mind that mocking endpoints causes the messages to be copied when they arrive on the mock.
That means Camel will use more memory. This may not be suitable when you send in a lot of messages.
{info}
h4. Mocking existing endpoints using the {{camel-test}} component
Instead of using the {{adviceWith}} to instruct Camel to mock endpoints, you can easily enable this behavior when using the {{camel-test}} Test Kit.
The same route can be tested as follows. Notice that we return {{"*"}} from the {{isMockEndpoints}} method, which tells Camel to mock all endpoints.
If you only want to mock all {{log}} endpoints you can return {{"log*"}} instead.
{snippet:id=e1|lang=java|title=isMockEndpoints using camel-test kit|url=camel/trunk/components/camel-test/src/test/java/org/apache/camel/test/patterns/IsMockEndpointsJUnit4Test.java}
h4. Mocking existing endpoints with XML DSL
If you do not use the {{camel-test}} component for unit testing (as shown above) you can use a different approach when using XML files for routes.
The solution is to create a new XML file used by the unit test and then include the intended XML file which has the route you want to test.
Suppose we have the route in the {{camel-route.xml}} file:
{snippet:id=e1|lang=xml|title=camel-route.xml|url=camel/trunk/components/camel-spring/src/test/resources/org/apache/camel/spring/mock/camel-route.xml}
Then we create a new XML file as follows, where we include the {{camel-route.xml}} file and define a spring bean with the class {{org.apache.camel.impl.InterceptSendToMockEndpointStrategy}} which tells Camel to mock all endpoints:
{snippet:id=e1|lang=xml|title=camel-route.xml|url=camel/trunk/components/camel-spring/src/test/resources/org/apache/camel/spring/mock/InterceptSendToMockEndpointStrategyTest.xml}
Then in your unit test you load the new XML file instead of {{camel-route.xml}}.
To only mock all [log] endpoints you can define the pattern in the constructor for the bean:
{code:xml}
<bean id="mockAllEndpoints" class="org.apache.camel.impl.InterceptSendToMockEndpointStrategy">
<constructor-arg index="0" value="log*"/>
</bean>
{code}
{include:Endpoint See Also}
* [Spring Testing]
* [Testing] |