为什么我的 Camel JUnit 测试用例生成器模板无法发送正文?

Why is my Camel JUnit test case producer template not able to send a body?

我正在尝试测试这样的路线:

from("s3://bucketName")
.process(exchange -> {exchange.getIn().setHeader(Exchange.FILE_NAME,MY_FILE_NAME);})
.log("File download Successful")
.to("file:" + FILE_PATH).routeId("mys3Route");

我的测试是这样写的:

@Test
public void testFileMovement() throws Exception {
    AdviceWith.adviceWith(context, "mys3Route", a -> {
        a.replaceFromWith("mock:s3Location");
        a.interceptSendToEndpoint("file:" + FILE_PATH).skipSendToOriginalEndpoint()
                .to("mock:anotherLocation");
    });
    MockEndpoint mockedToEndPoint = getMockEndpoint("mock:anotherLocation");
    mockedToEndPoint.setExpectedMessageCount(1);
    template.sendBody("mock:s3Location", "Just Text");
    mockedToEndPoint.assertIsSatisfied();
    Thread.sleep(5000);
}

每当我 运行 作为单元测试用例时,我都会收到此错误:

org.apache.camel.CamelExecutionException: Exception occurred during >execution on the exchange: Exchange[]

错误似乎出现在:org.apache.camel.impl.engine.DefaultProducerTemplate.extractResultBody(DefaultProducerTemplate.java:591)(存在于 camel 依赖项中)。

知道我做错了什么以及如何纠正吗?非常感谢任何解决和理解此问题的帮助。

对于初学者,您可能不应该将 consumer/From 端点替换为 MockEndpoint,只需使用直接端点。 MockEndpoints 仅支持生产者端点 (to),不应用作消费者端点 (from)。 MockEndpoints 旨在用作您要对消息正文、交换属性、接收到的消息等进行断言的路径上的点。

其次,如果您使用 AdviceWith you should set the isUseAdviceWith 为真并在使用 template.send 方法之前手动启动上下文。如果您使用或不使用 spring 引导注释,设置方式会有所不同。下面的示例仅使用简单的 CamelTestSupport。

第三,您很少需要在 camel 测试中使用拦截,请改用 weaveById, weaveByToURI with replace instead. In this case you're better off just fixing how your file-path and file-name is set by using property-placeholders。这样你就可以使用 useOverridePropertiesWithPropertiesComponent 和 junit 的 TemporaryFolder 功能。如果您需要读取 file-contents 测试文件或将某些内容复制到测试文件夹,Apache-commons IO FileUtils 也非常方便。

将 Thread.Sleep 与单元测试一起使用充其量是 hacky,应该避免。对于这种情况,我认为您没有理由使用它。 RouteId最好放在路由的最前面。

示例:

package com.example;

import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Properties;

import org.apache.camel.RoutesBuilder;
import org.apache.camel.builder.AdviceWithRouteBuilder;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.component.mock.MockEndpoint;
import org.apache.camel.test.junit4.CamelTestSupport;
import org.apache.commons.io.FileUtils;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;

public class ExampleTest extends CamelTestSupport {
    
    @Rule
    public TemporaryFolder temporaryFolder = new TemporaryFolder();
    File outputFolder;

    static final String FILE_NAME = "testfile.txt";

    @Test
    public void testFileMovement() throws Exception {

        context.getRouteDefinition("mys3Route")
            .adviceWith(context, new AdviceWithRouteBuilder(){

            @Override
            public void configure() throws Exception {

                replaceFromWith("direct:start");
                weaveAddLast()
                    .to("mock:result");
            } 
        });

        MockEndpoint resultMockEndpoint = getMockEndpoint("mock:result");
        resultMockEndpoint.setExpectedMessageCount(1);

        startCamelContext();
        template.sendBody("direct:start", "Just Text");

        File file = new File(outputFolder, FILE_NAME);
        assertEquals(true, file.exists());
        String fileContents = FileUtils.readFileToString(file, StandardCharsets.UTF_8);
        assertEquals("Just Text", fileContents);

        resultMockEndpoint.assertIsSatisfied();
    }

    @Override
    protected RoutesBuilder createRouteBuilder() throws Exception {
       
        return new RouteBuilder(){

            @Override
            public void configure() throws Exception {
                
                from("s3://bucketName")
                    .routeId("mys3Route")
                    .log("File download Successful")
                    .to("file:{{filepath}}?fileName={{filename}}");
            }
        };
    }

    @Override
    protected Properties useOverridePropertiesWithPropertiesComponent() {

        try {
            outputFolder = temporaryFolder.newFolder("output");
        } catch (IOException e) {
            e.printStackTrace();
        }

        Properties properties = new Properties();
        properties.put("filename", FILE_NAME);
        properties.put("filepath", outputFolder.getPath());

        return properties;
    }

    @Override
    public boolean isUseAdviceWith() {
        return true;
    }   
}
<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>${commons-io.version}</version>
</dependency>