Apache Camel SNMP 路由的简单单元测试 [英] Simple unit test for Apache Camel SNMP route
问题描述
我在编写一个工作的 Camel Spring-Boot 单元测试时遇到了一些麻烦,它测试了一个简单的 SNMP 路由.这是我目前所拥有的:
SnmpRoute.kt
open class SnmpRoute(private val snmpProperties: SnmpProperties, private val repository: IPduEventRepository) : RouteBuilder() {@抛出(异常::类)覆盖乐趣配置(){logger.debug("使用属性初始化 [{}]", snmpProperties)from("snmp:0.0.0.0:1161?protocol=udp&type=TRAP").process { 交换 ->//做东西}.bean(存储库,保存")}}
SnmpRouteTest.kt
@CamelSpringBootTest@SpringBootApplication@EnableAutoConfiguration打开类 SnmpRouteTest : CamelTestSupport() {对象 SnmpConstants {const val SNMP_TRAP = "<snmp><entry><oid>...datadatadata...</oid><value>123456</value></entry></snmp>const val MOCK_SNMP_ENDPOINT = "mock:snmp"}@嘲笑lateinit var snmpProperties: SnmpProperties@嘲笑lateinit var 存储库:IPduEventRepository@InjectMocks延迟初始化 var snmpRoute: SnmpRoute@EndpointInject(SnmpConstants.MOCK_SNMP_ENDPOINT)lateinit var mock:MockEndpoint@前有趣的设置(){initMocks(这个)}@抛出(异常::类)覆盖乐趣 createRouteBuilder(): RouteBuilder {返回 snmpRoute}@测试@抛出(异常::类)有趣的`测试SNMP端点`(){mock.expectedBodiesReceived(SnmpConstants.SNMP_TRAP)template.sendBody(SnmpConstants.MOCK_SNMP_ENDPOINT,SnmpConstants.SNMP_TRAP)mock.assertIsSatisfied()验证(存储库).保存(PduEvent(1234,PDU.TRAP))}}
然而,当我运行这个测试时,它失败了,因为 repository
模拟从来没有任何交互:
通缉但未调用:存储库.保存(PduEvent(requestId=1234, type=-89));->在 org.meanwhile.in.hell.camel.snmp.route.SnmpRouteTest.Test SNMP 端点(SnmpRouteTest.kt:61)实际上,与此模拟的交互为零.
有人能帮我理解为什么这不能正确交互吗?手动运行时,这可以正常工作并按预期保存.
现在我明白这是怎么回事了!您被测的 RouteBuilder
有一个 from("snmp")
.如果您希望在那里提供模拟消息进行测试,您需要将 snmp:
组件替换为 direct:
或 seda:
组件,在测试执行期间.
您当前的测试是将消息传递到 Mock 端点并验证它是否在那里收到.它不与真正的路由构建器交互.这就是为什么您的模拟端点断言确实通过了,但 Mockito.verify()
失败了.
TL;DR
假设您使用的是 Apache Camel 3.x,以下是操作方法.我对 Kotlin 不是很流利,所以我将展示如何在 Java 中做到这一点.
AdviceWithRouteBuilder.adviceWith(context, "route-id", routeBuilder -> {routeBuilder.replaceFromWith("direct:snmp-from");//用直接组件替换路由`route-id`的from部分});
- 您需要修改路由构建器代码以将 ID 分配给路由(例如,
route-id
) - 将路由开始处的 SNMP 组件替换为直接组件
- 将测试消息传送到
direct:
组件而不是 SNMP
TL;DR 结束.
完整的示例代码如下.
PojoRepo.java
@Component公共类 PojoRepo {公共无效保存(字符串主体){System.out.println(body);}}
SNMPDummyRoute.java
@Component公共类 SNMPDummyRoute 扩展了 RouteBuilder {PojoRepo pojoRepo;公共 SNMPDummyRoute(PojoRepo pojoRepo) {this.pojoRepo = pojoRepo;}@覆盖公共无效配置()抛出异常{from("snmp:0.0.0.0:1161?protocol=udp&type=TRAP").id("snmp-route").process(交换 -> {exchange.getMessage().setBody(String.format("Saw message [%s]", exchange.getIn().getBody()));}).to("log:snmp-log").bean(pojoRepo,保存");}}
SNMPDummyRoteTest.java
注意:这个类使用了CamelSpringBootRunner
,而不是扩展CamelTestSupport
,但核心思想是一样的.
来自下面的测试运行的日志.仔细查看 XML 片段,其中 SNMP 端点与直接组件交换.
2019-11-12 20:52:57.126 INFO 32560 --- [ main] o.a.c.component.snmp.SnmpTrapConsumer : 在 udp:0.0.0.0/1161 上启动陷阱消费者2019-11-12 20:52:58.363 INFO 32560 --- [main] o.a.c.component.snmp.SnmpTrapConsumer:使用 udp 协议在 udp:0.0.0.0/1161 上启动陷阱使用者2019-11-12 20:52:58.364 INFO 32560 --- [main] o.a.c.s.boot.SpringBootCamelContext:路由:snmp-route 开始并从:snmp://udp:0.0.0.0/1161 开始消费2019-11-12 20:52:58.368 INFO 32560 --- [main] o.a.c.s.boot.SpringBootCamelContext :共 1 条路由,其中 1 条已启动2019-11-12 20:52:58.370 INFO 32560 --- [main] o.a.c.s.boot.SpringBootCamelContext : Apache Camel 3.0.0-M4 (CamelContext: MyCamel) 在 2.645 秒内启动2019-11-12 20:52:59.670 INFO 32560 --- [main] o.a.c.i.engine.DefaultShutdownStrategy:开始正常关闭 1 条路由(超时 10 秒)2019-11-12 20:52:59.680 INFO 32560 --- [- ShutdownTask] o.a.c.component.snmp.SnmpTrapConsumer:在 udp:0.0.0.0/1161 上停止陷阱消费者2019-11-12 20:52:59.683 INFO 32560 --- [- ShutdownTask] o.a.c.i.engine.DefaultShutdownStrategy:路由:snmp-route shutdown complete,正在消耗:snmp://udp:0.0.0.0/11612019-11-12 20:52:59.684 INFO 32560 --- [main] o.a.c.i.engine.DefaultShutdownStrategy:在 0 秒内完成 1 条路线的正常关闭2019-11-12 20:52:59.687 INFO 32560 --- [main] o.a.c.s.boot.SpringBootCamelContext :路由:snmp-route 已停止,正在消耗:snmp://udp:0.0.0.0/11612019-11-12 20:52:59.689 INFO 32560 --- [ main] o.a.c.s.boot.SpringBootCamelContext :路由:snmp-route 被关闭并删除,正在消耗:snmp://udp:0.0.0.0/11612019-11-12 20:52:59.691 INFO 32560 --- [main] o.apache.camel.builder.AdviceWithTasks:AdviceWith 替换来自 [snmp:0.0.0.0:1161?protocol=udp&type=TRAP] 的输入 -->[直接:snmp-来自]2019-11-12 20:52:59.692 INFO 32560 --- [main] org.apache.camel.reifier.RouteReifier :AdviceWith 路由之后:Route(snmp-route)[From[direct:snmp-from] ->[process[Processor@0x589dfa6f], To[log:snmp-log], Bean[org.foo.bar.POJORepo$MockitoMock$868728200]]]2019-11-12 20:52:59.700 INFO 32560 --- [main] org.apache.camel.reifier.RouteReifier:作为 XML 之前/之后的建议路线:<?xml version="1.0" encoding="UTF-8" standalone="yes"?><route xmlns="http://camel.apache.org/schema/spring" customId="true" id="snmp-route"><from uri="snmp:0.0.0.0:1161?protocol=udp&type=TRAP"/><process id="process1"/><to id="to1" uri="log:snmp-log"/><bean id="bean1" method="save"/></路线><?xml version="1.0" encoding="UTF-8" standalone="yes"?><route xmlns="http://camel.apache.org/schema/spring" customId="true" id="snmp-route"><from uri="direct:snmp-from"/><process id="process1"/><to id="to1" uri="log:snmp-log"/><bean id="bean1" method="save"/></路线>2019-11-12 20:52:59.734 INFO 32560 --- [main] .i.e.InterceptSendToMockEndpointStrategy:建议端点 [log://snmp-log] 与模拟端点 [mock:log:snmp-log]2019-11-12 20:52:59.755 INFO 32560 --- [main] o.a.c.s.boot.SpringBootCamelContext :路由:snmp-route 开始并从:direct://snmp-from2019-11-12 20:52:59.834 INFO 32560 --- [main] snmp-log : Exchange[ExchangePattern: InOnly, BodyType: String, Body: Saw message [One]]2019-11-12 20:52:59.899 INFO 32560 --- [main] snmp-log : Exchange[ExchangePattern: InOnly, BodyType: String, Body: Saw message [Two]]2019-11-12 20:52:59.900 INFO 32560 --- [main] o.a.camel.component.mock.MockEndpoint :断言:mock://log:snmp-log 满足2019-11-12 20:53:01.903 INFO 32560 --- [ main] o.a.camel.component.mock.MockEndpoint :重新断言:mock://log:snmp-log 在 2000 毫秒后得到满足2019-11-12 20:53:01.992 INFO 32560 --- [ main] o.a.c.s.boot.SpringBootCamelContext : Apache Camel 3.0.0-M4 (CamelContext: MyCamel) 正在关闭2019-11-12 20:53:01.993 INFO 32560 --- [main] o.a.c.i.engine.DefaultShutdownStrategy:开始正常关闭 1 条路由(超时 10 秒)2019-11-12 20:53:01.996 INFO 32560 --- [- ShutdownTask] o.a.c.i.engine.DefaultShutdownStrategy:路由:snmp-route 关闭完成,正在消耗:direct://snmp-from2019-11-12 20:53:01.996 INFO 32560 --- [main] o.a.c.i.engine.DefaultShutdownStrategy:在 0 秒内完成 1 条路线的正常关闭
I'm having some trouble getting a working Camel Spring-Boot unit test written, that tests a simple SNMP route. Here is what I have so far:
SnmpRoute.kt
open class SnmpRoute(private val snmpProperties: SnmpProperties, private val repository: IPduEventRepository) : RouteBuilder() {
@Throws(Exception::class)
override fun configure() {
logger.debug("Initialising with properties [{}]", snmpProperties)
from("snmp:0.0.0.0:1161?protocol=udp&type=TRAP")
.process { exchange ->
// do stuff
}
.bean(repository, "save")
}
}
SnmpRouteTest.kt
@CamelSpringBootTest
@SpringBootApplication
@EnableAutoConfiguration
open class SnmpRouteTest : CamelTestSupport() {
object SnmpConstants {
const val SNMP_TRAP = "<snmp><entry><oid>...datadatadata...</oid><value>123456</value></entry></snmp>"
const val MOCK_SNMP_ENDPOINT = "mock:snmp"
}
@Mock
lateinit var snmpProperties: SnmpProperties
@Mock
lateinit var repository: IPduEventRepository
@InjectMocks
lateinit var snmpRoute: SnmpRoute
@EndpointInject(SnmpConstants.MOCK_SNMP_ENDPOINT)
lateinit var mock: MockEndpoint
@Before
fun setup() {
initMocks(this)
}
@Throws(Exception::class)
override fun createRouteBuilder(): RouteBuilder {
return snmpRoute
}
@Test
@Throws(Exception::class)
fun `Test SNMP endpoint`() {
mock.expectedBodiesReceived(SnmpConstants.SNMP_TRAP)
template.sendBody(SnmpConstants.MOCK_SNMP_ENDPOINT,
SnmpConstants.SNMP_TRAP)
mock.assertIsSatisfied()
verify(repository).save(PduEvent(1234, PDU.TRAP))
}
}
However, when I run this test, it fails as the repository
mock never has any interactions:
Wanted but not invoked:
repository.save(
PduEvent(requestId=1234, type=-89)
);
-> at org.meanwhile.in.hell.camel.snmp.route.SnmpRouteTest.Test SNMP endpoint(SnmpRouteTest.kt:61)
Actually, there were zero interactions with this mock.
Can someone help me understand why this isn't interacting correctly? When run manually, this works and saves as expected.
Now I see what is going on here!
Your RouteBuilder
under test has a from("snmp")
. If you wish to deliver a mock message there for testing, you need to swap the snmp:
component with something like a direct:
or seda:
component, during test execution.
Your current test is delivering a message to a Mock endpoint and verifying if it was received there. It does not interact with the real route builder. That's why your mock endpoint assertions do passed but Mockito.verify()
failed.
TL;DR
Presuming that you are using Apache Camel 3.x, here is how to do it. I'm not fluent in Kotlin so, I'll show how to do that in Java.
AdviceWithRouteBuilder.adviceWith(context, "route-id", routeBuilder -> {
routeBuilder.replaceFromWith("direct:snmp-from"); //Replaces the from part of the route `route-id` with a direct component
});
- You need to modify your route builder code to assign an ID to the route (say,
route-id
) - Replace the SNMP component at the start of the route with a direct component
- Deliver test messages to the
direct:
component instead of SNMP
TL;DR ends.
Full blown sample code below.
PojoRepo.java
@Component
public class PojoRepo {
public void save(String body){
System.out.println(body);
}
}
SNMPDummyRoute.java
@Component
public class SNMPDummyRoute extends RouteBuilder {
PojoRepo pojoRepo;
public SNMPDummyRoute(PojoRepo pojoRepo) {
this.pojoRepo = pojoRepo;
}
@Override
public void configure() throws Exception {
from("snmp:0.0.0.0:1161?protocol=udp&type=TRAP")
.id("snmp-route")
.process(exchange -> {
exchange.getMessage().setBody(String.format("Saw message [%s]", exchange.getIn().getBody()));
})
.to("log:snmp-log")
.bean(pojoRepo, "save");
}
}
SNMPDummyRoteTest.java
Note: This class uses CamelSpringBootRunner
instead of extending CamelTestSupport
, but the core idea is same.
@RunWith(CamelSpringBootRunner.class)
@SpringBootTest
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
@DisableJmx(false)
@MockEndpoints("log:*")
public class SNMPDummyRouteTest {
@MockBean
PojoRepo repo;
@EndpointInject("mock:log:snmp-log")
MockEndpoint mockEndpoint;
@Produce
ProducerTemplate testTemplate;
@Autowired
CamelContext camelContext;
@Test
public void testRoute() throws Exception {
AdviceWithRouteBuilder.adviceWith(camelContext,"snmp-route",routeBuilder -> {
routeBuilder.replaceFromWith("direct:snmp-from");
});
testTemplate.sendBody("direct:snmp-from","One");
testTemplate.sendBody("direct:snmp-from","Two");
mockEndpoint.expectedMinimumMessageCount(2);
mockEndpoint.setAssertPeriod(2_000L);
mockEndpoint.assertIsSatisfied();
Mockito.verify(repo, Mockito.atLeast(2)).save(anyString());
}
}
Logs from test run below. Take a closer look at the XML piece where the SNMP endpoint gets swapped in with a direct component.
2019-11-12 20:52:57.126 INFO 32560 --- [ main] o.a.c.component.snmp.SnmpTrapConsumer : Starting trap consumer on udp:0.0.0.0/1161
2019-11-12 20:52:58.363 INFO 32560 --- [ main] o.a.c.component.snmp.SnmpTrapConsumer : Started trap consumer on udp:0.0.0.0/1161 using udp protocol
2019-11-12 20:52:58.364 INFO 32560 --- [ main] o.a.c.s.boot.SpringBootCamelContext : Route: snmp-route started and consuming from: snmp://udp:0.0.0.0/1161
2019-11-12 20:52:58.368 INFO 32560 --- [ main] o.a.c.s.boot.SpringBootCamelContext : Total 1 routes, of which 1 are started
2019-11-12 20:52:58.370 INFO 32560 --- [ main] o.a.c.s.boot.SpringBootCamelContext : Apache Camel 3.0.0-M4 (CamelContext: MyCamel) started in 2.645 seconds
2019-11-12 20:52:59.670 INFO 32560 --- [ main] o.a.c.i.engine.DefaultShutdownStrategy : Starting to graceful shutdown 1 routes (timeout 10 seconds)
2019-11-12 20:52:59.680 INFO 32560 --- [ - ShutdownTask] o.a.c.component.snmp.SnmpTrapConsumer : Stopped trap consumer on udp:0.0.0.0/1161
2019-11-12 20:52:59.683 INFO 32560 --- [ - ShutdownTask] o.a.c.i.engine.DefaultShutdownStrategy : Route: snmp-route shutdown complete, was consuming from: snmp://udp:0.0.0.0/1161
2019-11-12 20:52:59.684 INFO 32560 --- [ main] o.a.c.i.engine.DefaultShutdownStrategy : Graceful shutdown of 1 routes completed in 0 seconds
2019-11-12 20:52:59.687 INFO 32560 --- [ main] o.a.c.s.boot.SpringBootCamelContext : Route: snmp-route is stopped, was consuming from: snmp://udp:0.0.0.0/1161
2019-11-12 20:52:59.689 INFO 32560 --- [ main] o.a.c.s.boot.SpringBootCamelContext : Route: snmp-route is shutdown and removed, was consuming from: snmp://udp:0.0.0.0/1161
2019-11-12 20:52:59.691 INFO 32560 --- [ main] o.apache.camel.builder.AdviceWithTasks : AdviceWith replace input from [snmp:0.0.0.0:1161?protocol=udp&type=TRAP] --> [direct:snmp-from]
2019-11-12 20:52:59.692 INFO 32560 --- [ main] org.apache.camel.reifier.RouteReifier : AdviceWith route after: Route(snmp-route)[From[direct:snmp-from] -> [process[Processor@0x589dfa6f], To[log:snmp-log], Bean[org.foo.bar.POJORepo$MockitoMock$868728200]]]
2019-11-12 20:52:59.700 INFO 32560 --- [ main] org.apache.camel.reifier.RouteReifier : Adviced route before/after as XML:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<route xmlns="http://camel.apache.org/schema/spring" customId="true" id="snmp-route">
<from uri="snmp:0.0.0.0:1161?protocol=udp&type=TRAP"/>
<process id="process1"/>
<to id="to1" uri="log:snmp-log"/>
<bean id="bean1" method="save"/>
</route>
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<route xmlns="http://camel.apache.org/schema/spring" customId="true" id="snmp-route">
<from uri="direct:snmp-from"/>
<process id="process1"/>
<to id="to1" uri="log:snmp-log"/>
<bean id="bean1" method="save"/>
</route>
2019-11-12 20:52:59.734 INFO 32560 --- [ main] .i.e.InterceptSendToMockEndpointStrategy : Adviced endpoint [log://snmp-log] with mock endpoint [mock:log:snmp-log]
2019-11-12 20:52:59.755 INFO 32560 --- [ main] o.a.c.s.boot.SpringBootCamelContext : Route: snmp-route started and consuming from: direct://snmp-from
2019-11-12 20:52:59.834 INFO 32560 --- [ main] snmp-log : Exchange[ExchangePattern: InOnly, BodyType: String, Body: Saw message [One]]
2019-11-12 20:52:59.899 INFO 32560 --- [ main] snmp-log : Exchange[ExchangePattern: InOnly, BodyType: String, Body: Saw message [Two]]
2019-11-12 20:52:59.900 INFO 32560 --- [ main] o.a.camel.component.mock.MockEndpoint : Asserting: mock://log:snmp-log is satisfied
2019-11-12 20:53:01.903 INFO 32560 --- [ main] o.a.camel.component.mock.MockEndpoint : Re-asserting: mock://log:snmp-log is satisfied after 2000 millis
2019-11-12 20:53:01.992 INFO 32560 --- [ main] o.a.c.s.boot.SpringBootCamelContext : Apache Camel 3.0.0-M4 (CamelContext: MyCamel) is shutting down
2019-11-12 20:53:01.993 INFO 32560 --- [ main] o.a.c.i.engine.DefaultShutdownStrategy : Starting to graceful shutdown 1 routes (timeout 10 seconds)
2019-11-12 20:53:01.996 INFO 32560 --- [ - ShutdownTask] o.a.c.i.engine.DefaultShutdownStrategy : Route: snmp-route shutdown complete, was consuming from: direct://snmp-from
2019-11-12 20:53:01.996 INFO 32560 --- [ main] o.a.c.i.engine.DefaultShutdownStrategy : Graceful shutdown of 1 routes completed in 0 seconds
这篇关于Apache Camel SNMP 路由的简单单元测试的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!