You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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();
    }
}

为什么这样改?

  1. CamelTestSupport自动管理CamelContext的启动、停止,不需要你手动写setup()/destroy()方法
  2. 路由编织(AdviceWith)可以一次性完成,代码更简洁
  3. 不需要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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 07:22:24