Apache Camel SNMP 路由的简单单元测试 [英] Simple unit test for Apache Camel SNMP route

查看:30
本文介绍了Apache Camel SNMP 路由的简单单元测试的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在编写一个工作的 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部分});

  1. 您需要修改路由构建器代码以将 ID 分配给路由(例如,route-id)
  2. 将路由开始处的 SNMP 组件替换为直接组件
  3. 将测试消息传送到 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,但核心思想是一样的.

<预><代码>@RunWith(CamelSpringBootRunner.class)@SpringBootTest@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)@DisableJmx(false)@MockEndpoints("日志:*")公共类 SNMPDummyRouteTest {@MockBeanPojoRepo 仓库;@EndpointInject("mock:log:snmp-log")MockEndpoint mockEndpoint;@生产ProducerTemplate 测试模板;@自动连线CamelContext camelContext;@测试public void testRoute() 抛出异常 {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());}}

来自下面的测试运行的日志.仔细查看 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&amp;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
});

  1. You need to modify your route builder code to assign an ID to the route (say, route-id)
  2. Replace the SNMP component at the start of the route with a direct component
  3. 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&amp;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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆