【问题标题】:Camel unit test with cameltestsupport, template is always null带有cameltestsupport的骆驼单元测试,模板始终为空
【发布时间】:2018-03-05 19:37:34
【问题描述】:

我正在使用 Camel 进行简单的单元测试。我要做的就是从文件中读取 JSON 内容(在资源下),将其发送到 Java 类进行验证 - 这是我要测试的路线。无论我做什么,模板(我用于 sendBody(json) 的模板始终为空。这是我的代码:

public class RouteTests extends CamelTestSupport {

    @EndpointInject(uri = "mock:result")
    protected MockEndpoint resultEndpoint;

    @Produce(uri = "direct:start")
    protected ProducerTemplate template;

    @Autowired
    JSONObject testJson;

    @Before
    public void setUp() throws Exception {
        try {
            final ObjectMapper objectmapper = new ObjectMapper();
            final ClassLoader loader = Thread.currentThread().getContextClassLoader();
            final InputStream stream = loader.getResourceAsStream("test.json");
            testJson = new JSONObject ((Map)objectmapper.readValue(stream, Map.class));

            // Start Camel
            context = new DefaultCamelContext();
            context.addRoutes(createRouteBuilder());
            context.start();
        }
        catch (IOException e) {
        }
    }

    @Test
    public void testSendMatchingMessage() throws Exception {
        //resultEndpoint.expectedBodiesReceived(expectedBody);
        resultEndpoint = getMockEndpoint("mock:result");
        //resultEndpoint = context.getEndpoint("mock:result", MockEndpoint.class);
        resultEndpoint.expectedMessageCount(1);
        template.sendBody("direct:start", testJson);
        resultEndpoint.assertIsSatisfied();
    }

    @Override
    protected RouteBuilder createRouteBuilder() {
        return new RouteBuilder() {
            public void configure() {
                from("direct:start")
                        .filter().method(ValidationProcessor.class, "validate")
                        .to("mock:result");
            }
        };
    }

    @Override
    protected JndiRegistry createRegistry() throws Exception {
        JndiRegistry jndi = super.createRegistry();
        jndi.bind("ValidationProcessor", new ValidationProcessor", ());

        return jndi;
    }
}

我遇到的问题:

  1. 最初结果端点也始终为空。 (我使用 FilterTest.java 作为参考)。然后我不得不做一个明确的

     resultEndpoint = getMockEndpoint("mock:result");
    

    解决这个问题。

  2. 然后我读到我必须重写 createRegistry,但我不知道如何绑定。我只是使用了我的验证类的名称,但我不知道这是否正确。

    但模板始终为空。 null pointer exception (NPE) 位于

     template.sendBody("direct:start", testJson);
    

如有必要,还请指点我阅读。 Apache Camel 文档链接到的参考代码甚至没有我在 setUp 方法中所做的 Camel 的开头。

【问题讨论】:

  • 你不应该自己创建 CamelContext 而是让CamelTestSupport 为你创建它。作为其设置的一部分,它设置了一些 IoC 的东西。但请注意,您有 Spring @Autowired 不是 Camel,如果是这样,您需要扩展 CamelSpringTestSupport。如果您同时使用 Camel 和 Spring,请参阅 camel-test-spring 中的单元测试。此外,CiA2 书中有一整章是关于测试的。
  • 会听从您的建议,谢谢。我也要去读你提到的那本书的章节。
  • 那是需要 createRegistry 覆盖的时候吗?即使以下解决方案有效,我仍然不清楚:D
  • 重写 createRegistry 是一个巧妙的技巧,允许从 java 代码绑定 bean,这在使用 spring 时可能有点棘手。书中的第 4 章涵盖了各种 Camel Registry 实现。
  • 我认为代码无法编译 - 靠近 jndi.bind("ValidationProcessor", new ValidationProcessor",(这也在初始修订版中)。这由奇怪的语法突出显示。

标签: java unit-testing apache-camel


【解决方案1】:

我认为您错过了CamelTestSupport 为您提供的许多真正有用的东西。它有自己的 setUp 方法,您应该重写它。我相信你的测试应该看起来像这样:

public class RouteTests extends CamelTestSupport {

    private JSONObject testJson;

    @Override
    public void setUp() throws Exception {
        // REALLY important to call super
        super.setUp();

        ObjectMapper objectmapper = new ObjectMapper();
        ClassLoader loader = Thread.currentThread().getContextClassLoader();
        InputStream stream = loader.getResourceAsStream("test.json");
        testJson = new JSONObject(objectmapper.readValue(stream, Map.class));
    }

    @Override
    protected RouteBuilder createRouteBuilder() {
        return new RouteBuilder() {
            @Override
            public void configure() {
                from("direct:start")
                        .filter().method(ValidationProcessor.class, "validate")
                        .to("mock:result");
            }
        };
    }

    @Test
    public void testSendMatchingMessage() throws Exception {
        MockEndpoint resultEndpoint = getMockEndpoint("mock:result");
        resultEndpoint.expectedMessageCount(1);
        template.sendBody("direct:start", testJson);
        resultEndpoint.assertIsSatisfied();
    }
}

实际上我会完全删除setUp 的覆盖并将测试数据的读取放入测试方法本身。那么数据的用途就很清楚了,就可以去掉testJson这个字段了。

public class RouteTests extends CamelTestSupport {

    @Override
    protected RouteBuilder createRouteBuilder() {
        return new RouteBuilder() {
            @Override
            public void configure() {
                from("direct:start")
                        .filter().method(ValidationProcessor.class, "validate")
                        .to("mock:result");
            }
        };
    }

    @Test
    public void testSendMatchingMessage() throws Exception {
        ObjectMapper objectmapper = new ObjectMapper();
        ClassLoader loader = Thread.currentThread().getContextClassLoader();
        InputStream stream = loader.getResourceAsStream("test.json");
        JSONObject testJson = new JSONObject(objectmapper.readValue(stream, Map.class));

        MockEndpoint resultEndpoint = getMockEndpoint("mock:result");
        resultEndpoint.expectedMessageCount(1);
        template.sendBody("direct:start", testJson);
        resultEndpoint.assertIsSatisfied();
    }
}

到这里,就简单多了。

【讨论】:

  • 一定会试试这个并回帖,谢谢你这么详细的回复:)
  • 当然成功了!非常感谢,这样就简单多了。那么在我的情况下,为什么 template 或 resultEndPoint 为空?我只是不明白。 svn.apache.org/repos/asf/camel/trunk/components/camel-test/src/… 的 FilterTest 不起作用:(
  • tbh 我不确定。我不倾向于使用@-annotations,并且通常以这种方式编写我的路由测试。
  • 在测试之间我们需要做一些清理工作吗?我问的原因是第一次测试(带有正 o/p JSON)在 1 毫秒内完成,而第二次测试(预期失败)需要 10 秒。它只是停了一会儿,所以我想知道是否需要在每次测试之间重置一些东西
  • 当您执行resultEndpoint.assertIsSatisfied() 时,它会等待允许任何正在进行的异步交换在失败前完成。默认值为 10 秒,如下所述:github.com/apache/camel/blob/master/camel-core/src/main/docs/…
【解决方案2】:

尝试像这样从 Camel 上下文创建生产者模板:

public class RouteTests extends CamelTestSupport {

    @EndpointInject(uri = "mock:result")
    protected MockEndpoint resultEndpoint;

    protected ProducerTemplate template;

    @Autowired
    JSONObject testJson;

    @Before
    public void setUp() throws Exception {
        try {
            final ObjectMapper objectmapper = new ObjectMapper();
            final ClassLoader loader = Thread.currentThread().getContextClassLoader();
            final InputStream stream = loader.getResourceAsStream("test.json");
            testJson = new JSONObject ((Map)objectmapper.readValue(stream, Map.class));
            //start camel
            context = new DefaultCamelContext();
            context.addRoutes(createRouteBuilder());
            context.start();
            template = context.createProducerTemplate();
        }
        catch (IOException e) {
        }
    }

    @Test
    public void testSendMatchingMessage() throws Exception {
        //resultEndpoint.expectedBodiesReceived(expectedBody);
        resultEndpoint = getMockEndpoint("mock:result");
        //resultEndpoint = context.getEndpoint("mock:result", MockEndpoint.class);
        resultEndpoint.expectedMessageCount(1);
        template.sendBody("direct:start", testJson);
        resultEndpoint.assertIsSatisfied();
    }

    @Override
    protected RouteBuilder createRouteBuilder() {
        return new RouteBuilder() {
            public void configure() {
                from("direct:start")
                        .filter().method(ValidationProcessor.class, "validate")
                        .to("mock:result");
            }
        };
    }

    @Override
    protected JndiRegistry createRegistry() throws Exception {
        JndiRegistry jndi = super.createRegistry();
        jndi.bind("ValidationProcessor", new ValidationProcessor());

        return jndi;
    }
}

所以在你的 setUp() 中添加:

template = context.createProducerTemplate();

并删除@Produce(uri = "direct:start")

【讨论】:

  • 成功了,非常感谢 :) 但是 createRegistry 甚至是必需的吗???
  • 顺便说一句,我的问题是什么?我仍然想了解我在哪里错过了什么?如果你能解释它会很有帮助:)
  • 这个答案没有利用CamelTestSupport - 没有必要自己创建上下文或模板。
猜你喜欢
  • 2020-03-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-11-26
  • 2017-12-27
  • 1970-01-01
  • 1970-01-01
  • 2023-01-28
相关资源
最近更新 更多