测试 Camel 路由时如何正确使用 Mocks?
How do I properly use Mocks when testing Camel routes?
我正在尝试编写一个 Camel 测试来检查以确保基于内容的路由器正确路由 XML 文件。这是我的 blueprint.xml:
中的点和路线
<endpoint uri="activemq:queue:INPUTQUEUE" id="jms.queue.input" />
<endpoint uri="activemq:queue:QUEUE1" id="jms.queue.1" />
<endpoint uri="activemq:queue:QUEUE2" id="jms.queue.2" />
<route id="general-jms.to.specific-jms">
<from ref="jms.queue.input" />
<choice>
<when>
<xpath>//object-type = '1'</xpath>
<log message="Sending message to queue: QUEUE1" />
<to ref="jms.queue.1" />
</when>
<when>
<xpath>//object-type = '2'</xpath>
<log message="Sending message to queue: QUEUE2" />
<to ref="jms.queue.2" />
</when>
<otherwise>
<log message="No output was able to be determined based on the input." />
</otherwise>
</choice>
</route>
现在,我要做的就是发送一个 <object-type>
为 1 的示例源文件,并验证它是否路由到正确的队列 (QUEUE1) 并且是正确的数据 (应该只将整个 XML 文件发送到 QUEUE1)。这是我的测试代码:
public class RouteTest extends CamelBlueprintTestSupport {
@Override
protected String getBlueprintDescriptor() {
return "/OSGI-INF/blueprint/blueprint.xml";
}
@Override
public String isMockEndpointsAndSkip() {
return "activemq:queue:QUEUE1";
}
@Test
public void testQueue1Route() throws Exception {
getMockEndpoint("mock:activemq:queue:QUEUE1").expectedBodiesReceived(context.getTypeConverter().convertTo(String.class, new File("src/test/resources/queue1-test.xml")));
template.sendBody("activemq:queue:INPUTQUEUE", context.getTypeConverter().convertTo(String.class, new File("src/test/resources/queue1-test.xml")));
assertMockEndpointsSatisfied();
}
}
当我 运行 这个测试时,我看到我放在路由定义中的日志消息说它正在将它发送到 QUEUE1,但是 JUnit 测试失败并显示以下错误消息:java.lang.AssertionError: mock://activemq:queue:QUEUE1 接收到的消息计数。预期:<1> 但实际为:<0>.
有人可以帮助我理解我做错了什么吗?
我的理解是 Camel 会自动模拟 QUEUE1 端点,因为我覆盖了 isMockEndpointsAndSkip()
并提供了 QUEUE1 端点 uri。我认为这意味着我应该能够在 getMockEnpoint()
方法中使用该端点,只需将 "mock:" 附加到 uri 的开头即可。然后我应该有一个模拟端点,我可以在上面设置期望值(即必须有输入文件)。
如果我有什么不清楚的地方请告诉我,非常感谢任何帮助!
在这方面工作了一段时间之后,我想出的唯一对我有效的解决方案是在我的测试 class 中使用 createRouteBuilder()
方法添加一条路由到在我的 blueprint.xml 文件中定义的路由末尾的模拟端点。然后我可以根据我的期望检查模拟端点。下面是我测试的最终代码class。蓝图 XML 保持不变。
public class RouteTest extends CamelBlueprintTestSupport {
@Override
protected String getBlueprintDescriptor() {
return "/OSGI-INF/blueprint/blueprint.xml";
}
@Test
public void testQueue1Route() throws Exception {
getMockEndpoint("mock:QUEUE1").expectedBodiesReceived(context.getTypeConverter().convertTo(String.class, new File("src/test/resources/queue1-test.xml")));
template.sendBody("activemq:queue:INPUTQUEUE", context.getTypeConverter().convertTo(String.class, new File("src/test/resources/queue1-test.xml")));
assertMockEndpointsSatisfied();
}
@Test
public void testQueue2Route() throws Exception {
getMockEndpoint("mock:QUEUE2").expectedBodiesReceived(context.getTypeConverter().convertTo(String.class, new File("src/test/resources/queue2-test.xml")));
template.sendBody("activemq:queue:INPUTQUEUE", context.getTypeConverter().convertTo(String.class, new File("src/test/resources/queue2-test.xml")));
assertMockEndpointsSatisfied();
}
@Override
protected RouteBuilder createRouteBuilder() throws Exception {
return new RouteBuilder() {
public void configure() throws Exception {
from("activemq:queue:QUEUE1").to("mock:QUEUE1");
from("activemq:queue:QUEUE2").to("mock:QUEUE2");
}
};
}
}
虽然此解决方案有效,但我不完全理解为什么我不能只使用 isMockEndpointsAndSkip()
而不是必须在现有 blueprint.xml 路线的末尾手动定义新路线。据我了解,使用 return "*";
定义 isMockEndpointsAndSkip()
将为 blueprint.xml 文件中定义的所有端点注入模拟端点。然后你可以检查你对那些模拟端点的期望。但出于某种原因,这对我不起作用。
解决方法是使用CamelTestSupport.replaceRouteFromWith
.
此方法完全没有任何文档,但在我这样调用时对我有用:
public class FooTest extends CamelTestSupport {
@Override
public void setUp() throws Exception {
replaceRouteFromWith("route-id", "direct:route-input-replaced");
super.setUp();
}
// other stuff ...
}
这也将阻止路由的 from
目的地的原始消费者的启动。例如,这意味着当要测试具有 activemq 消费者的路由时,不再需要 activemq 实例 运行。
我正在尝试编写一个 Camel 测试来检查以确保基于内容的路由器正确路由 XML 文件。这是我的 blueprint.xml:
中的点和路线<endpoint uri="activemq:queue:INPUTQUEUE" id="jms.queue.input" />
<endpoint uri="activemq:queue:QUEUE1" id="jms.queue.1" />
<endpoint uri="activemq:queue:QUEUE2" id="jms.queue.2" />
<route id="general-jms.to.specific-jms">
<from ref="jms.queue.input" />
<choice>
<when>
<xpath>//object-type = '1'</xpath>
<log message="Sending message to queue: QUEUE1" />
<to ref="jms.queue.1" />
</when>
<when>
<xpath>//object-type = '2'</xpath>
<log message="Sending message to queue: QUEUE2" />
<to ref="jms.queue.2" />
</when>
<otherwise>
<log message="No output was able to be determined based on the input." />
</otherwise>
</choice>
</route>
现在,我要做的就是发送一个 <object-type>
为 1 的示例源文件,并验证它是否路由到正确的队列 (QUEUE1) 并且是正确的数据 (应该只将整个 XML 文件发送到 QUEUE1)。这是我的测试代码:
public class RouteTest extends CamelBlueprintTestSupport {
@Override
protected String getBlueprintDescriptor() {
return "/OSGI-INF/blueprint/blueprint.xml";
}
@Override
public String isMockEndpointsAndSkip() {
return "activemq:queue:QUEUE1";
}
@Test
public void testQueue1Route() throws Exception {
getMockEndpoint("mock:activemq:queue:QUEUE1").expectedBodiesReceived(context.getTypeConverter().convertTo(String.class, new File("src/test/resources/queue1-test.xml")));
template.sendBody("activemq:queue:INPUTQUEUE", context.getTypeConverter().convertTo(String.class, new File("src/test/resources/queue1-test.xml")));
assertMockEndpointsSatisfied();
}
}
当我 运行 这个测试时,我看到我放在路由定义中的日志消息说它正在将它发送到 QUEUE1,但是 JUnit 测试失败并显示以下错误消息:java.lang.AssertionError: mock://activemq:queue:QUEUE1 接收到的消息计数。预期:<1> 但实际为:<0>.
有人可以帮助我理解我做错了什么吗?
我的理解是 Camel 会自动模拟 QUEUE1 端点,因为我覆盖了 isMockEndpointsAndSkip()
并提供了 QUEUE1 端点 uri。我认为这意味着我应该能够在 getMockEnpoint()
方法中使用该端点,只需将 "mock:" 附加到 uri 的开头即可。然后我应该有一个模拟端点,我可以在上面设置期望值(即必须有输入文件)。
如果我有什么不清楚的地方请告诉我,非常感谢任何帮助!
在这方面工作了一段时间之后,我想出的唯一对我有效的解决方案是在我的测试 class 中使用 createRouteBuilder()
方法添加一条路由到在我的 blueprint.xml 文件中定义的路由末尾的模拟端点。然后我可以根据我的期望检查模拟端点。下面是我测试的最终代码class。蓝图 XML 保持不变。
public class RouteTest extends CamelBlueprintTestSupport {
@Override
protected String getBlueprintDescriptor() {
return "/OSGI-INF/blueprint/blueprint.xml";
}
@Test
public void testQueue1Route() throws Exception {
getMockEndpoint("mock:QUEUE1").expectedBodiesReceived(context.getTypeConverter().convertTo(String.class, new File("src/test/resources/queue1-test.xml")));
template.sendBody("activemq:queue:INPUTQUEUE", context.getTypeConverter().convertTo(String.class, new File("src/test/resources/queue1-test.xml")));
assertMockEndpointsSatisfied();
}
@Test
public void testQueue2Route() throws Exception {
getMockEndpoint("mock:QUEUE2").expectedBodiesReceived(context.getTypeConverter().convertTo(String.class, new File("src/test/resources/queue2-test.xml")));
template.sendBody("activemq:queue:INPUTQUEUE", context.getTypeConverter().convertTo(String.class, new File("src/test/resources/queue2-test.xml")));
assertMockEndpointsSatisfied();
}
@Override
protected RouteBuilder createRouteBuilder() throws Exception {
return new RouteBuilder() {
public void configure() throws Exception {
from("activemq:queue:QUEUE1").to("mock:QUEUE1");
from("activemq:queue:QUEUE2").to("mock:QUEUE2");
}
};
}
}
虽然此解决方案有效,但我不完全理解为什么我不能只使用 isMockEndpointsAndSkip()
而不是必须在现有 blueprint.xml 路线的末尾手动定义新路线。据我了解,使用 return "*";
定义 isMockEndpointsAndSkip()
将为 blueprint.xml 文件中定义的所有端点注入模拟端点。然后你可以检查你对那些模拟端点的期望。但出于某种原因,这对我不起作用。
解决方法是使用CamelTestSupport.replaceRouteFromWith
.
此方法完全没有任何文档,但在我这样调用时对我有用:
public class FooTest extends CamelTestSupport {
@Override
public void setUp() throws Exception {
replaceRouteFromWith("route-id", "direct:route-input-replaced");
super.setUp();
}
// other stuff ...
}
这也将阻止路由的 from
目的地的原始消费者的启动。例如,这意味着当要测试具有 activemq 消费者的路由时,不再需要 activemq 实例 运行。