我想调整单元和集成测试用例,以测试所有功能流。有人能分享你的想法吗?我可以创建一个模拟端点来观察文件创建的目录,并通过多个路径进一步处理它们,并将文件移动到不同的目录。
- 监视
/hello
目录以创建新文件 - 如果存在基于文件前缀的文件,则使用容器名称更新标头
- 根据文件名上传到适当的azure blob容器
- 进行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文件操作从测试资源文件夹中以字符串、字节数组或流的形式读取文件,并将其作为主体与标头CamelFileName
和CamelFileEventType
一起发送到目标路由。
我还建议将直接路由视为函数,使其更易于测试。这意味着,您可以拥有只按正确顺序调用子路由的父路由,而不是从一条路由跳到另一条路由。
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:updateHeaders
、direct:uploadFileToBlob
和direct: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 的示例