假设我在单独的RouteBuilder类中创建了路径。它看起来像:
我想在没有JMS代理且没有DB的情况下对此路由进行单元测试。我知道我可以模拟我的处理器实现,但这还不够。我不想改变这条路线(假设我在jar文件中得到了这个类)。据我所知,从Camel in Action(第6.2.6节)中,为了能够使用端点和其他东西的模拟,我需要更改我的路由端点定义(在本书的示例中,这是“mina:tcp:/”的更改/ miranda“to”mock:miranda“etc)。
是否可以在不改变路径定义的情况下完全隔离测试流量? 如果我将RouteBuilder作为一个单独的类,我是否被迫以某种方式“复制”路由定义并手动更改它?是不是测试了错误的东西?
我对Camel很陌生,对我来说,能够在开发路线时进行隔离单元测试真的很酷。只是为了能够改变一些东西,进行小测试,观察结果等等。
答案 0 :(得分:24)
假设RouteBuilder类具有硬编码端点,那么测试起来有点困难。但是,如果RouteBuilder使用端点uris的属性占位符,那么您通常可以使用一组不同的端点uris进行单元测试。正如骆驼书第6章所解释的那样。
如果它们是硬编码的,那么您可以在单元测试中使用带有功能的建议,如下所示:http://camel.apache.org/advicewith.html
在Camel 2.7中,我们可以更轻松地操作路线,因此您可以移除零件,更换零件等。这就是链接谈论的编织物。
例如,为了模拟向数据库端点发送消息,您可以使用上面的内容并将to替换为另一个将其发送到mock的位置。
在以前的版本中,你可以使用interceptSendToEndpoint技巧,这也在Camel书中有所介绍(见第6.3.3节)
哦,你也可以用模拟组件替换组件,如第169页所示。现在在Camel 2.8以后,模拟组件将不再抱怨它不知道的uri参数。这意味着更容易在每个组件级别上使用模拟替换组件。
答案 1 :(得分:4)
我有
<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单元测试在多种环境中的一个更好的例子
答案 2 :(得分:0)
虽然你可以使用拦截和建议来交换克劳斯易卜生的端点
回答,我认为让你的路线接受Endpoint
会好得多
实例,以便您的测试不会与生产端点URI相关联。
例如,假设您的RouteBuilder
看起来像
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
是手动创建的,因此您可以确保只创建了测试中的路线答案 3 :(得分:0)
如果您使用的是Spring(这通常是个好主意),我想 分享我的方法。
您的生产路线是特殊种类的春豆 我的路线
@Component
public class MyRoute extends RouteBuilder {
public static final String IN = "jms://inqueue";
@Override
public void configure() throws Exception {
from(IN)
.process(exchange -> {
// Do stuff with exchange
})
.to("activemq:somequeue");
}
}
因此,在测试中,您可以像这样轻松地覆盖它(这是一个 spring java config内部(到测试类)类):
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();
}
};
}
}
注意super.configure()将安装您的生产路线,您可能会 使用interceptFrom,interceptSendToEndpoint注入测试代码:例如 引发异常。
我还添加了一些帮助路线。通过此路由,我可以测试文件是否具有 是在输出文件夹中生成的,可能是JMS使用者...
@Bean
public RouteBuilder createOutputRoute() {
return new RouteBuilder() {
@Override
public void configure() {
fromF(FILE_IN,
outputDir)
.to("mock:output")
.routeId("doneRoute");
};
对于JMS / JDBC / ...,还有Mockrunner。使用测试配置中的以下代码,您几乎可以完成工作:将JMS Connection Factory替换为模拟实现,因此现在您甚至可以将某些内容放入JMS并从jms读取(使用上述简单的骆驼路线)进行验证。不要忘记在模拟上创建队列。
@Bean(JMS_MOCK_CONNECTION_FACTORY) @主 公共ConnectionFactory jmsConnectionFactory(){ return(new JMSMockObjectFactory())。getMockQueueConnectionFactory(); }
我不喜欢AdviseWith,是的,它很灵活,但是它要求您在测试中手动处理camelContext,这对我来说太麻烦了。我不想将该代码放入数百个测试中,也不想围绕它创建一个框架。子类化CamelTestSupport也可能是一个问题,例如,如果您使用两个库,这两个库都需要您对子类进行子类化,并且您可能拥有自己的测试类层次结构,而您看不到CamelTestSupport。我尝试在测试中不要使用类层次结构,以使测试独立。子类化意味着您需要做一些魔术(您不会在测试中直接看到该代码)。如果您修改该魔术,则会影响很多测试。我为此使用spring java配置集。