Junit 如何在ApacheCamel中对生产路线进行单元测试?
假设我在单独的RouteBuilder类中创建了路由。它看起来像:Junit 如何在ApacheCamel中对生产路线进行单元测试?,junit,mocking,routes,integration,apache-camel,Junit,Mocking,Routes,Integration,Apache Camel,假设我在单独的RouteBuilder类中创建了路由。它看起来像: 从JMS队列抓取消息 进行一些转换、验证等 根据验证结果转发到特定的JMS队列,并在数据库中保存一些内容 我想在没有JMS代理和DB的情况下对这个路由进行单元测试。我知道我可以模仿我的处理器实现,但这还不够。我不想改变这个路由(假设我在jar文件中得到了这个类)。据我从Camel in Action(第6.2.6节)了解,为了能够使用端点模拟和其他东西,我需要更改我的路由端点定义(在本书的示例中,这是“mina:tcp://
- 从JMS队列抓取消息
- 进行一些转换、验证等
- 根据验证结果转发到特定的JMS队列,并在数据库中保存一些内容
我对Camel很陌生,对我来说,在开发路由时能够进行独立的单元测试真的很酷。只是为了能够改变一些东西,运行小测试,观察结果等等。假设RouteBuilder类有硬编码的端点,那么测试就有点困难了。但是,如果RouteBuilder为端点URI使用属性占位符,那么您通常可以为单元测试使用不同的端点URI集。如骆驼书第6章所述 如果它们是硬编码的,那么您可以在单元测试中使用advice with功能,如下所示: 在Camel 2.7中,我们可以更轻松地操纵路线,因此您可以移除零件、更换零件等。这就是link所讨论的编织内容 例如,要模拟将消息发送到数据库端点,可以使用上面的命令,并将to替换为另一个命令,将其发送到模拟 在以前的版本中,您可以使用interceptSendToEndpoint技巧,这在Camel手册(第6.3.3节)中也有介绍 哦,您也可以用模拟组件替换组件,如第169页所示。现在在Camel 2.8以后的版本中,mock组件将不再抱怨它不知道的uri参数。这意味着在每个组件级别上用mock替换组件要容易得多。
<bean id="properties" class="org.apache.camel.component.properties.PropertiesComponent">
<property name="location" value="classpath:shop.properties"/>
</bean>
<route>
<from uri="direct://stock"/>
<to uri="{{stock.out}}"/>
</route>
在我的spring文件中,然后在测试类路径上的shop.properties中,我有一个stock.out=xxxx,它在运行时被替换,因此我可以选择不同的路由,一个用于运行时,另一个用于测试
在6.1.6多环境单元测试中有一个更好的例子,您可以根据Claus Ibsen的建议使用截取和建议来交换端点 回答,我认为允许您的路由接受
端点
实例,这样您的测试就不会耦合到生产端点URI
例如,假设您有一个类似于
public class MyRoute extends RouteBuilder {
@Override
public void configure() throws Exception {
from("http://someapi/someresource")
.process(exchange -> {
// Do stuff with exchange
})
.to("activemq:somequeue");
}
}
您可以这样注入端点:
public class MyRoute extends RouteBuilder {
private Endpoint in;
private Endpoint out;
// This is the constructor your production code can call
public MyRoute(CamelContext context) {
this.in = context.getEndpoint("http://someapi/someresource");
this.out = context.getEndpoint("activemq:somequeue");
}
// This is the constructor your test can call, although it would be fine
// to use in production too
public MyRoute(Endpoint in, Endpoint out) {
this.in = in;
this.out = out;
}
@Override
public void configure() throws Exception {
from(this.in)
.process(exchange -> {
// Do stuff with exchange
})
.to(this.out);
}
}
然后可以像这样进行测试:
public class MyRouteTest {
private Endpoint in;
private MockEndpoint out;
private ProducerTemplate producer;
@Before
public void setup() {
CamelContext context = new DefaultCamelContext();
this.in = context.getEndpoint("direct:in");
this.out = context.getEndpoint("mock:direct:out", MockEndpoint.class);
this.producer = context.createProducerTemplate();
this.producer.setDefaultEndpoint(this.in);
RouteBuilder myRoute = new MyRoute(this.in, this.out);
context.addRoutes(myRoute);
context.start();
}
@Test
public void test() throws Exception {
this.producer.sendBody("Hello, world!");
this.out.expectedMessageCount(1);
this.out.assertIsSatisfied();
}
}
这有以下优点:
- 您的测试非常简单,易于理解,甚至不需要扩展
或其他助手类CamelTestSupport
是手工创建的,因此您可以确保只创建了测试中的路由CamelContext
- 测试不关心生产路线URI
- 如果需要,您仍然可以方便地将端点URI硬编码到route类中
@Bean
public RouteBuilder createOutputRoute() {
return new RouteBuilder() {
@Override
public void configure() {
fromF(FILE_IN,
outputDir)
.to("mock:output")
.routeId("doneRoute");
};
如果路由是xml格式的,我们如何添加测试?+1用于提及属性替换。这也是我最喜欢的技术,因为我发现它比
adviceWith
更快,并且在我的测试类中可读性更强(您还可以重写方法:useOverridePropertiesWithPropertiesComponent()
)
static class TestConfig extends IntegrationTestConfig {
@Bean
public MyRoute myRoute(){
return new MyRoute() {
@Override
public void configure() throws Exception {
interceptFrom(MyRoute.IN)
.choice()
.when(x -> delayThisMessagePredicate.matches(x)) //make the predicate modifiable between tests
.to("log:delayed")
.delay(5000)
.endChoice();
super.configure();
}
};
}
}
@Bean
public RouteBuilder createOutputRoute() {
return new RouteBuilder() {
@Override
public void configure() {
fromF(FILE_IN,
outputDir)
.to("mock:output")
.routeId("doneRoute");
};