使用Arquillian单元测试无默认容器,遇ValidationException报错求助
解决Arquillian容器不匹配错误 + Camel路由测试优化
首先,你遇到的ValidationException是因为Arquillian默认需要一个DEFAULT容器来运行测试,但你的类路径里没有添加任何Arquillian容器适配器依赖,导致它找不到可用的容器。
针对你的Camel路由测试场景,我给你两种解决方案:
方案一:放弃Arquillian,用Camel原生测试框架(推荐)
你已经继承了CamelTestSupport,这个类是Apache Camel专门为路由测试设计的,它已经帮你处理了CamelContext的生命周期、Mock端点管理等问题,完全不需要Arquillian。我们可以简化你的测试代码:
修改后的测试类
public class TestFiles extends CamelTestSupport { private MockEndpoint afterCSV; private MockEndpoint afterXML; private MockEndpoint afterTXT; private MockEndpoint afterError; // 告诉Camel要测试的路由类 @Override protected RoutesBuilder createRouteBuilder() throws Exception { return new App(); } // 在测试前配置路由编织(AdviceWith)和Mock端点 @Override protected void preSetup() throws Exception { super.preSetup(); // 一次性完成所有路由编织,比多次调用更简洁 context.getRouteDefinition("camelmarian").adviceWith(context, new AdviceWithRouteBuilder() { @Override public void configure() throws Exception { weaveById("mockcsv").after().to("mock:csv"); weaveById("mockxml").after().to("mock:xml"); weaveById("mocktext").after().to("mock:text"); weaveById("mockerror").after().to("mock:error"); } }); // 获取Mock端点实例 afterCSV = getMockEndpoint("mock:csv"); afterXML = getMockEndpoint("mock:xml"); afterTXT = getMockEndpoint("mock:text"); afterError = getMockEndpoint("mock:error"); } @Test public void testReceived() throws InterruptedException { File tempFile = new File("src/main/resources/temp/data.xml"); boolean isMoved = tempFile.renameTo(new File("src/main/resources/temp2/" + tempFile.getName())); if (!isMoved) { fail("Failed to move test file to monitored directory"); } afterXML.expectedMessageCount(1); assertMockEndpointsSatisfied(); } @Test public void testError() throws InterruptedException { File tempFile = new File("src/main/resources/temp/data4.pl"); boolean isMoved = tempFile.renameTo(new File("src/main/resources/temp2/" + tempFile.getName())); if (!isMoved) { fail("Failed to move test file to monitored directory"); } afterError.expectedMessageCount(1); assertMockEndpointsSatisfied(); } }
为什么这样改?
CamelTestSupport自动管理CamelContext的启动、停止,不需要你手动写setup()/destroy()方法- 路由编织(AdviceWith)可以一次性完成,代码更简洁
- 不需要Arquillian的容器依赖,测试启动更快,更轻量
方案二:保留Arquillian,添加容器依赖
如果你因为项目架构需求必须使用Arquillian,需要添加一个嵌入式容器适配器(比如Weld SE,用于CDI环境):
1. 添加Maven依赖
在你的pom.xml中加入以下测试依赖:
<dependency> <groupId>org.jboss.arquillian.container</groupId> <artifactId>arquillian-weld-se-embedded-1.1</artifactId> <version>1.0.0.Final</version> <scope>test</scope> </dependency> <dependency> <groupId>org.jboss.weld.se</groupId> <artifactId>weld-se-core</artifactId> <version>2.4.6.Final</version> <scope>test</scope> </dependency>
2. 完善Deployment归档
添加CDI所需的beans.xml(空文件即可,放在src/test/resources/META-INF/下),并修改归档构建代码:
@Deployment(testable = true) public static Archive<?> createArchive() { return ShrinkWrap.create(JavaArchive.class) .addClass(App.class) .addClass(CamelContextSetup.class) .addClass(WrongFileException.class) .addClass(XmlProcessor.class) .addClass(CsvProcessor.class) .addClass(TextProcessor.class) .addAsResource("META-INF/beans.xml"); // 启用CDI }
3. 调整测试类
注意:不要同时继承CamelTestSupport和使用Arquillian,两者的生命周期管理会冲突。改为纯Arquillian+CDI的方式:
@RunWith(Arquillian.class) public class TestFiles { @Inject private CamelContextSetup camelContextSetup; @Test public void testReceived() throws InterruptedException { File tempFile = new File("src/main/resources/temp/data.xml"); boolean isMoved = tempFile.renameTo(new File("src/main/resources/temp2/" + tempFile.getName())); if (!isMoved) { fail("Failed to move test file"); } camelContextSetup.getAfterXML().expectedMessageCount(1); assertMockEndpointsSatisfied(camelContextSetup.getAfterXML().getCamelContext()); } // testError方法同理调整 }
总结
- 如果你只是想测试Camel路由逻辑,方案一是最优选择:轻量、快速、符合Camel测试的最佳实践
- 如果你需要在Arquillian容器环境中测试(比如集成CDI、EJB等),再选择方案二,记得添加容器依赖并处理好生命周期冲突
内容的提问来源于stack exchange,提问作者Marian Sichitiu
相关产品推荐
相关产品推荐

