如何使用 @Configuration class 覆盖 xml 中定义的 spring bean 定义以进行 jerseytest

How to override spring bean definition defined in xml with @Configuration class for jerseytest

一段时间以来,我一直在努力解决这个问题,但无法让它发挥作用。我正在使用 spring 版本 3.2.3.RELEASE,我认为这可能会导致我遇到一些问题。我的目标是用一个导入了 configuration.The 的配置文件覆盖 xml 中定义的 bean带有模拟实现的实现。但是,这对我不起作用。如有任何建议,我们将不胜感激。

这是我的 bean 定义 class,我在其中定义了几个 bean。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context.xsd">

    <import resource="rest-common.xml"/>

    <context:property-placeholder  location="classpath:module.properties"/>


    <bean name="vcheckResource" class="com.foo.vcheck.resources.VcheckResource" />

    <bean name="vcheckProvider" class="com.foo.vcheck.provider.VcheckProvider" />

    <bean name="Vcheck" class="com.foo.vcheck.provider.VcheckMessageRouter" />

</beans>

这里是生产@Configuration class 我在其中导入 bean 配置文件。

@Configuration
@Import(RestAppConfig.class)
@ImportResource({VcheckAppConfig.ModuleResources})
public class VcheckAppConfig {

    public static final String ModuleResources =  "classpath:bcpbx-api-vcheck-rest-beans.xml";

}

这是我的测试配置 class,我想在其中使用我的 Mockito 模拟覆盖实现,并且在单元测试中应该使用这些模拟 class 注入生产代码。但是,无论出于何种原因,xml 配置中的 bean 都不会被覆盖。如果我删除导入,它将使用来自此 class 的 bean,所以我知道这是有效的。这可能与 spring 的 3.x 版本有关吗?

@Configuration
@Import(VcheckAppConfig.class)
public class TestAppConfig {

    @Bean
    public Account testAccount() {
        return new Account("TEST_ACCOUNT", new Vendor("TEST_VENDOR"));
    }

    @Bean(name ="vcheckResource")
    public VcheckResource vcheckResource() {
        return new VcheckResource(vcheckProvider(), new UUIDGenerator());
    }

    @Bean(name="vcheckProvider")
    public IVcheckProvider vcheckProvider() {
        System.out.println("CALLIGN GET MOCK");
        return Mockito.mock(VcheckProvider.class);
    }

    @Bean
    public IMessageRouter messageRouter() {
        return Mockito.mock(IMessageRouter.class);
    }

    @Bean
    public ICommandResponseCallbackRegistry responseRegistry() {
        return Mockito.mock(ICommandResponseCallbackRegistry.class);
    }

}

spring似乎无法做到这一点。

How do I override a Spring bean definition yet still reference the overridden bean?

我转换为使用 spring-mockito 并使用另一个 bean xml 文件来添加模拟。然后导入两个配置 xml 文件。这在我的单元测试中与 spring mockito 一起工作得很好。我确实必须更改我的 mockito 版本以使用 1.9.0 以与 spring mockito 兼容。

https://bitbucket.org/kubek2k/springockito/wiki/Home

@Configuration
@ImportResource({VcheckAppConfig.ModuleResources, TestAppConfig.MockModuleResources})
public class TestAppConfig {

    public static final String MockModuleResources = "classpath:bcpbx-api-vcheck-rest-beans-mock.xml";

    @Bean
    public Account testAccount() {
        return new Account("TEST_ACCOUNT", new Vendor("TEST_VENDOR"));
    }
}

这是我的模拟示例,我在其中使用简单模拟重写了我的提供者的实现。我能够

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:mockito="http://www.mockito.org/spring/mockito"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context.xsd
    http://www.mockito.org/spring/mockito http://www.mockito.org/spring/mockito.xsd">

    <mockito:mock id="vcheckProvider" class="com.foo.vcheck.provider.VcheckProvider"  />

</beans>

作为旁注,我将 post 这也是因为它是一个很好的解决方案,允许我使用 spring 依赖项注入进行球衣测试。

public abstract class AbstractSpring3JerseyTest implements ApplicationContextAware {

    private static final Logger logger = Logger.getLogger(AbstractSpring3JerseyTest.class.getName());

    private JerseyTest jerseyTest;

    private ApplicationContext applicationContext;

    @Before
    public void setup() throws Exception {
        jerseyTest.setUp();
    }

    @After
    public void tearDown() throws Exception {
        jerseyTest.tearDown();
    }

    protected Application configure(ApplicationContext appContext) {
        ResourceConfig resourceConfig = ResourceConfig.forApplication(new RestApplication());
        resourceConfig.property("contextConfig", appContext);
        resourceConfig.register(SpringLifecycleListener.class).register(RequestContextFilter.class);
        resourceConfig.packages(getResourcePackages());
        resourceConfig.register(new RestAuthenticationFilter());
        resourceConfig.property(ServerProperties.RESPONSE_SET_STATUS_OVER_SEND_ERROR, "true");
        resourceConfig.register(new LoggingFilter(logger, 20000));

        return resourceConfig;
    }

    protected abstract String[] getResourcePackages();

    public static void setDebugLevel(Level level) {
        Logger anonymousLogger = LogManager.getLogManager().getLogger("");
        Handler[] handlers = anonymousLogger.getHandlers();
        anonymousLogger.setLevel(level);
        for (Handler h : handlers) {
            if (h instanceof ConsoleHandler)
                h.setLevel(level);
        }
    }

    public final WebTarget target() {
        return jerseyTest.target();
    }

    public final WebTarget target(final String path) {
        return jerseyTest.target().path(path);
    }

    public ApplicationContext getApplicationContext() {
        return applicationContext;
    }

    /**
     * Set the ApplicationContext that this object runs in. Normally this call
     * will be used to initialize the object.
     * <p>
     * Invoked after population of normal bean properties but before an init
     * callback such as
     * {@link org.springframework.beans.factory.InitializingBean#afterPropertiesSet()}
     * or a custom init-method. Invoked after
     * {@link ResourceLoaderAware#setResourceLoader},
     * {@link ApplicationEventPublisherAware#setApplicationEventPublisher} and
     * {@link MessageSourceAware}, if applicable.
     * 
     * @param applicationContext
     *            the ApplicationContext object to be used by this object
     * @throws ApplicationContextException
     *             in case of context initialization errors
     * @throws BeansException
     *             if thrown by application context methods
     * @see org.springframework.beans.factory.BeanInitializationException
     */
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
        jerseyTest = new JerseyTest(configure(applicationContext)) {
        };
    }
}

这是一个简单的测试,用于验证所有部件是否正常工作。

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { TestAppConfig.class } )
public class TestVcheckResourceJersey extends AbstractSpring3JerseyTest {


    @Inject
    IVcheckProvider vcheckProvider;

    @Test
    public void testCheckNpanxx() throws ProviderException {
        Assert.assertNotNull(vcheckProvider);
    }
}