单元测试骆驼路线使用骆驼测试支持



我想调整单元和集成测试用例,以测试所有功能流。有人能分享你的想法吗?我可以创建一个模拟端点来观察文件创建的目录,并通过多个路径进一步处理它们,并将文件移动到不同的目录。

  1. 监视/hello目录以创建新文件
  2. 如果存在基于文件前缀的文件,则使用容器名称更新标头
  3. 根据文件名上传到适当的azure blob容器
  4. 进行api调用,并在文件处理后将其移动到/success目录

FileWatcherRoute.java

@Service
public class FileWatcherRoute extends RouteBuilder {
@Value("${watcher-base-url}")
private String baseUrl;
@Value("${watcher-subscription-key}")
private String subscriptionKey;
@Override
public void configure() {
Processor logResponse = exchange -> log
.info("The response code is: {}", exchange.getIn().getHeader(Exchange.HTTP_RESPONSE_CODE));
from("file-watch:hello?events=CREATE&antInclude=**/*.csv&recursive=true")
.routeId("fileWatch")
.to("direct:updateHeaders")
.end();
from("direct:updateHeaders")
.routeId("updateHeaders")
.choice()
.when((exchange -> exchange.getIn().getHeader(Exchange.FILE_NAME).toString().trim().matches("\d{8}_\d{4}(_Inventory.csv)")))
.setHeader("CamelAzureStorageBlobContainerName", constant(AppConstants.STORE))
.when(exchange -> exchange.getIn().getHeader(Exchange.FILE_NAME).toString().trim().matches("\d{8}-\d{6}_Idle_Inventory_\d{4}.csv"))
.setHeader("CamelAzureStorageBlobContainerName",constant(AppConstants.IDLE_FILE))
.toD("direct:uploadFileToBlob")
.end();
from("direct:uploadFileToBlob")
.routeId("uploadFile")
.log("Container Name: ${header.CamelAzureStorageBlobContainerName}")
.toD("azure-storage-blob://{accName}/${header.CamelAzureStorageBlobContainerName}?blobName=${header.CamelFileName}&operation=uploadBlockBlob&serviceClient=#serviceClient")
.to("direct:startRestApi")
.log("${header.CamelFileName} Uploaded to ${header.CamelAzureStorageBlobContainerName} Container Successfully")
.end();

from("direct:startRestApi")
.routeId("restCall")
.setHeader(Exchange.HTTP_METHOD, constant("GET"))
.setHeader("Content-Type",constant("application/json"))
.setHeader("Ocp-Apim-Subscription-Key",constant(subscriptionKey))
.to(baseUrl)
.to("direct:processedFiles")
.process(logResponse)
.end();
from("direct:processedFiles")
.routeId("fileProcessing")
.choice()
.when(exchange -> exchange.getIn().getHeader(Exchange.HTTP_RESPONSE_CODE).equals(200))
.to("file://success")
.otherwise()
.to("file://error")
.end();
}
}

FileWatcherRouteTest.java

@CamelSpringBootTest
@SpringBootTest
@MockEndpoints
@UseAdviceWith
public class FileWatcherRouteTest {
@Autowired
CamelContext camelContext;
@Autowired
ProducerTemplate producerTemplate;
@EndpointInject("mock:processedFiles")
MockEndpoint mockEndpoint;
@Test
void when_new_file_created_should_update_header_with_container_name_and_upload_to_container() throws Exception {
AdviceWith.adviceWith(camelContext, "fileWatch", routeBuilder -> {
routeBuilder.replaceFromWith("direct:file-watch");
});
camelContext.start();
mockEndpoint.assertIsSatisfied();
}
}

MockEndpoint只支持生产者端点。这是因为它被设计用于对Exchanges和Messages执行断言。

例如:

  • 给定的MockEndpoint是否接收到正确数量的消息
  • 消息正文与预期内容是否匹配
  • 如果向MockEndpoint提供了所需的标头

在测试路由时,您应该使用ProducerTemplate发送方法来启动测试中的路由,使用您想要测试的任何主体、标头和属性。

在您的情况下,您可以使用java文件操作从测试资源文件夹中以字符串、字节数组或流的形式读取文件,并将其作为主体与标头CamelFileNameCamelFileEventType一起发送到目标路由。

我还建议将直接路由视为函数,使其更易于测试。这意味着,您可以拥有只按正确顺序调用子路由的父路由,而不是从一条路由跳到另一条路由。

from("file-watch:hello?events=CREATE&antInclude=**/*.csv&recursive=true")
.routeId("fileWatch")
.to("direct:processNewFile")
// "Parent route"
from("direct:processNewFile")
.routeId("processCreatedFile")
.to("direct:updateHeaders")
.to("direct:uploadFileToBlob")
.to("direct:processedFiles")

这使您可以轻松地为direct:updateHeadersdirect:uploadFileToBlobdirect:processedFiles编写单独的测试

例如:

  • 测试direct:uploadFileToBlob是否在某个必需的标头丢失或无效时抛出正确的异常
  • 测试direct:uploadFileToBlob是否正确处理azure的连接异常
  • 测试direct:processedFiles是否将文件放置到正确的文件夹中

如果您想测试文件输出,可以使用JUnitsTemporaryFolder创建临时文件夹,然后使用文件生成器端点将其作为目标。路由完成后,您可以使用基本的assertEquals和文件操作来检查输出是否符合测试要求。

Apache Commons IO也是一个非常方便的测试库,用于从资源中读取文件并将文件复制到TemporaryFolder。

将示例与文件、ProducerTemplate、Commons IO和CamelTestSupport结合使用:

package com.example;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import org.apache.camel.Exchange;
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 inputFolder;
File outputFolder;
@Test
public void temporaryFolderExampleTest() throws Exception {
context.adviceWith(context.getRouteDefinition("processInputFile"), 
new AdviceWithRouteBuilder(){
@Override
public void configure() throws Exception {

replaceFromWith("direct:start");
weaveAddLast()
.to("mock:result");
}
}
);
MockEndpoint resultMockEndpoint = getMockEndpoint("mock:result");
resultMockEndpoint.expectedMessageCount(1);
resultMockEndpoint.message(0).body().isEqualTo("Hello world!");
InputStream body = fetchFileFromResourcesFolderAsStream("test-files/Hello.txt");
Map<String, Object> headers = new HashMap<>();
headers.put(Exchange.FILE_NAME, "Hello.txt");
startCamelContext();
template.sendBodyAndHeaders("direct:start", body, headers);
resultMockEndpoint.assertIsSatisfied();
File resultFile = new File(outputFolder, "Hello.txt");
assertEquals(true, resultFile.exists());
// FileUtils from commons-io/commons-io/2.11.0
String result = FileUtils.readFileToString(resultFile, StandardCharsets.UTF_8);
assertEquals("Hello world!", result);
}
@Test
public void pollEnrichExampleTest() throws Exception {
context.adviceWith(context.getRouteDefinition("pollEnrichExample"), 
new AdviceWithRouteBuilder(){
@Override
public void configure() throws Exception {
weaveAddLast()
.to("mock:result");
}
}
);
MockEndpoint resultMockEndpoint = getMockEndpoint("mock:result");
resultMockEndpoint.expectedMessageCount(1);
resultMockEndpoint.message(0).body().isEqualTo("Hello");
File resourceFile = fetchFileFromResourcesFolder("test-files/Hello.txt");
File testFile = new File(outputFolder, "Hello.txt");
FileUtils.copyFile(resourceFile, testFile);

startCamelContext();
template.sendBody("direct:pollEnrichExample", null);
resultMockEndpoint.assertIsSatisfied();
}
@Override
protected RoutesBuilder createRouteBuilder() throws Exception {

return new RouteBuilder() {
@Override
public void configure() throws Exception {

from("file:{{file.input}}")
.routeId("processInputFile")
.convertBodyTo(String.class)
.setBody(simple("${body} world!"))
.log("${body}")
.to("file:{{file.output}}");
from("direct:pollEnrichExample")
.routeId("pollEnrichExample")
.pollEnrich("file:{{file.output}}", 3000)
.convertBodyTo(String.class)
.log("${body}");
}
};
}
// use of placeholder properties and configuration files is highly encouraged
@Override
protected Properties useOverridePropertiesWithPropertiesComponent() {

try {
inputFolder = temporaryFolder.newFolder("input");
outputFolder = temporaryFolder.newFolder("output");
} catch (Exception e) {
e.printStackTrace();
}
Properties prop = new Properties();
prop.setProperty("file.input", inputFolder.getPath());
prop.setProperty("file.output", outputFolder.getPath());
return prop;
}
@Override
public boolean isUseAdviceWith() {
return true;
}
public File fetchFileFromResourcesFolder(String pathInResources){

ClassLoader classLoader = ExampleTest.class.getClassLoader();
return new File(classLoader.getResource(pathInResources).getFile());
}
public InputStream fetchFileFromResourcesFolderAsStream(String pathInResources){
try {
return new FileInputStream(fetchFileFromResourcesFolder(pathInResources));   
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.11.0</version>
</dependency>

以上使用Camel 3.4.4 的示例

最新更新