【问题标题】:spring camel test using multiple contexts使用多个上下文的弹簧骆驼测试
【发布时间】:2016-02-18 16:33:14
【问题描述】:

我使用 Spring 在不同的 xml 中有两个骆驼上下文(A 和 B)。当我只加载一个上下文时,我的 junit 可以工作,但是当我尝试加载两个上下文时,端点注入运行 junit 失败。

那么,有人有一个示例如何使用 Spring Camel 使用多个上下文进行测试?

春季测试

public class BaseSpringTest extends CamelSpringTestSupport
{
    protected AbstractXmlApplicationContext createApplicationContext()
    {
        return new ClassPathXmlApplicationContext("camel-config.xml");
    }
} 

我的档案camel-config.xml

<beans>
 <context:annotation-config/>
 <import resource="classpath:camel-test-dao.xml" />
 <import resource="classpath:camel-contextA.xml"/>
 <import resource="classpath:camel-contextB.xml"/>
</beans>

我的背景:

<camelContext xmlns="camel.apache.org/schema/spring" id="contextA"> 
 ...
</camelContext>
<camelContext xmlns="camel.apache.org/schema/spring" id="contextB"> 
...
</camelContext>

我的单元测试,注入失败Endpoint

@EndpointInject(uri = "direct:myroute", context="contextB")
private Endpoint eFooTest;

堆栈跟踪:

org.apache.camel.spring.GenericBeansException: Error post processing bean: com.mycompany.test.FooTest; nested exception is java.lang.NullPointerException
  at org.apache.camel.spring.CamelBeanPostProcessor.postProcessBeforeInitialization(CamelBeanPostProcessor.java:154)
  at org.apache.camel.test.spring.CamelSpringTestSupport.postProcessTest(CamelSpringTestSupport.java:62)
  at org.apache.camel.test.junit4.CamelTestSupport.doSetUp(CamelTestSupport.java:319)
  at org.apache.camel.test.junit4.CamelTestSupport.setUp(CamelTestSupport.java:238)
  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
  at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
  at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
  at java.lang.reflect.Method.invoke(Method.java:606)
  at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
  at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
  at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
  at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:24)
  at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
  at org.junit.rules.TestWatcher$1.evaluate(TestWatcher.java:55)
  at org.junit.rules.TestWatcher$1.evaluate(TestWatcher.java:55)
  at org.junit.rules.RunRules.evaluate(RunRules.java:20)
  at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
  at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
  at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
  at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
  at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
  at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
  at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
  at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
  at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
  at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
  at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
  at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
  at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
  at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
  at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
  at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
Caused by: java.lang.NullPointerException
  at org.apache.camel.impl.CamelPostProcessorHelper.matchContext(CamelPostProcessorHelper.java:84)
  at org.apache.camel.impl.DefaultCamelBeanPostProcessor$1.doWith(DefaultCamelBeanPostProcessor.java:181)
  at org.apache.camel.util.ReflectionHelper.doWithFields(ReflectionHelper.java:73)
  at org.apache.camel.impl.DefaultCamelBeanPostProcessor.injectFields(DefaultCamelBeanPostProcessor.java:168)
  at org.apache.camel.impl.DefaultCamelBeanPostProcessor.postProcessBeforeInitialization(DefaultCamelBeanPostProcessor.java:82)
  at org.apache.camel.spring.CamelBeanPostProcessor.postProcessBeforeInitialization(CamelBeanPostProcessor.java:148)
  ... 31 more

显然 CamelBeanPostProcessor 有一个错误,当有多个上下文时,会返回空值!

if (contexts != null && contexts.size() == 1) {

@XmlTransient
private final DefaultCamelBeanPostProcessor delegate = new DefaultCamelBeanPostProcessor() {
    @Override
    public CamelContext getOrLookupCamelContext() {
        if (camelContext == null) {
            if (camelId != null) {
                LOG.trace("Looking up CamelContext by id: {} from Spring ApplicationContext: {}", camelId, applicationContext);
                camelContext = applicationContext.getBean(camelId, CamelContext.class);
            } else {
                // lookup by type and grab the single CamelContext if exists
                LOG.trace("Looking up CamelContext by type from Spring ApplicationContext: {}", applicationContext);
                Map<String, CamelContext> contexts = applicationContext.getBeansOfType(CamelContext.class);
                if (contexts != null && contexts.size() == 1) {
                    camelContext = contexts.values().iterator().next();
                }
            }
        }
        return camelContext;
    }

Camel 2.16.2 Spring 4.1.5 JDK 1.7 JDK 1.8

【问题讨论】:

  • 在你的 beanPostProcessor xml 元素中添加一个 'camelId',或者不使用它,让默认的 beanprocessor 被注册?
  • 这段代码是默认的 beanpostprocessor DefaultCamelBeanPostProcessor.java 不是我的 :)
  • 我说的不是默认实现,而是默认配置。默认情况下,在 xml 配置中,对于每个 元素,camel 定义一个 beanPostProcessor,该 beanPostProcessor 使用设置为 camelContext id 的属性“camelId”进行初始化。在您显示的代码中,您会看到当 camelId != null 时,会在 applicationContext 中查找 camelContext
  • 感谢@JérémieB 的帮助。我有。我的 spring 上下文是这样配置的: camel.apache.org/schema/spring" id="contextA"> camel.apache.org/schema/spring" id="contextB"> 当我尝试从上下文中获取端点时,我不能。 @EndpointInject(uri = "direct:myroute", context="contextB")

标签: apache-camel


【解决方案1】:

感谢@Jorge-c,但是使用 routeContext 我们继续只有一个 CamelContext。

要在单元测试中使用多重上下文,请不要使用 CamelSpringTestSupport,这是一个错误。

public class BaseSpringTest extends CamelSpringTestSupport {...}

使用“@RunWith(SpringJUnit4ClassRunner.class)”

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("/camel-my-root-spring-config.xml")
public class BaseSpringJUnit4 
{
  @EndpointInject(uri = "direct:myroute", context="contextB")
  private Endpoint eFooTest;
}

这行得通! 别忘了在端点注解中明确地加上 context="contextB"

Camel 2.16.2 Spring 4.1.5 JDK 1.7 JDK 1.8

【讨论】:

    【解决方案2】:

    我也为此苦苦挣扎了一段时间。最后,我管理了一个解决方法,它允许我使用生产中使用的原始路由 xml 文件,但将其组合成一个单一的骆驼上下文,以便能够将其用于测试。这样我就可以为 bean 端点注入模拟,并通过在模拟上断言来检查完整的过程。

    有两个不同的捆绑包。一个来自发票,另一个来自电子邮件。路线编排流程。

    首先,我将生产 xml 文件中的路由外部化。发票包的 Spring 上下文 (invoicing-spring-context.xml) 和路由 (invoicing-routes.xml) 文件:

    <?xml version="1.0" encoding="UTF-8"?>
    <beans ...>
        ...
        <camelContext id="invoicingCamelContext"
            xmlns="http://camel.apache.org/schema/spring">
            <routeContextRef ref="invoicingRoutes"/>
        </camelContext>
    </beans>
    
    <?xml version="1.0" encoding="UTF-8"?>
    <beans ...>
        <routeContext id="invoicingRoutes" xmlns="http://camel.apache.org/schema/spring">
            <route id="planner" autoStartup="true">
                <from uri="quartz://planner?cron=0+0+23+16+*+?" />
                <to uri="direct:invoicing" />
            </route>
    
            <route id="invoicing" autoStartup="true">
                <from uri="direct:invoicing?exchangePattern=InOut" />
                <to uri="bean:invoicer?method=generateInvoices" />
                <to uri="direct-vm:emailing" />
            </route>
        </routeContext>
    </beans>
    

    用于电子邮件包的 Spring 上下文 (emailing-spring-context.xml) 和路由 (emailing-routes.xml):

    <?xml version="1.0" encoding="UTF-8"?>
    <beans ...>
        ...
        <camelContext id="emailingCamelContext"
            xmlns="http://camel.apache.org/schema/spring">
            <routeContextRef ref="emailingRoutes"/>
        </camelContext>
    </beans>
    
    <?xml version="1.0" encoding="UTF-8"?>
    <beans ...>
        <routeContext id="emailingRoutes" xmlns="http://camel.apache.org/schema/spring">
            <route id="emailing" autoStartup="true">
                <from uri="direct-vm:emailing" />
                <to uri="bean:emailer?method=createEmails" />
                <to uri="bean:emailer?method=sendEmails" />
            </route>
        </routeContext>
    </beans>
    

    然后出于测试目的,我创建了另一个导入两个路由文件的 spring 上下文 (complete-process-test-spring-context.xml):

    <?xml version="1.0" encoding="UTF-8"?>
    <beans ...>
        ...
        <camelContext id="completeProcessTestCamelContext"
            xmlns="http://camel.apache.org/schema/spring">      
            <routeContextRef ref="invoicingRoutes"/>
            <routeContextRef ref="emailingRoutes"/>
        </camelContext>
    </beans>
    

    测试类看起来像:

    public class CompleteProcessTest extends CamelSpringTestSupport {
        @Test
        public void completeProcess() {
            ...
    
            invoicerMock.generateInvoices(EasyMock.isA(Exchange.class));
            emailerMock.createEmails(EasyMock.isA(Exchange.class));
            emailerMock.sendEmails(EasyMock.isA(Exchange.class));
    
            EasyMock.replay(invoicerMock);
            EasyMock.replay(emailerMock);
    
            this.template.requestBody(this.context.getEndpoint("direct://invoicing"), "");
    
            EasyMock.verify(invoicerMock);
            EasyMock.verify(emailerMock);
        }
    
        @Override
        protected AbstractApplicationContext createApplicationContext() {
            return new ClassPathXmlApplicationContext("classpath:/META-INF/spring/invoicing-routes.xml",
                    "classpath:/META-INF/spring/emailing-routes.xml",
                    "classpath:/META-INF/spring/complete-process-test-spring-context.xml");
        }
    
        ...
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-10-27
      • 1970-01-01
      • 2020-10-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-01-23
      • 2017-12-21
      相关资源
      最近更新 更多