自动装配由EasyMock工厂方法生成的bean?

时间:2011-06-14 06:47:59

标签: java spring easymock autowired factory-method

我有一个对我来说真的很奇怪的问题。我有以下设置:

界面:

package com.example;

public interface SomeDependency {
}

弹簧组件:

package com.example;

@Component
public class SomeClass {
}

带有由EasyMock生成的模拟bean的spring test配置:

<beans ....>
    <context:component-scan base-package="com.example"/>

    <bean id="someInterfaceMock" class="org.easymock.EasyMock" factory-method="createMock">
        <constructor-arg value="com.example.SomeDependency" />
    </bean> 
</beans>

单元测试:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("/testconfig.xml")
public class SomeClassTest {

    @Autowired
    SomeClass someClass;

    @Autowired
    SomeDependency someDependency;

    @Test
    public void testSomeClass() throws Exception {
        assertNotNull(someClass);
    }

    @Test
    public void testSomeDependency() throws Exception {
        assertNotNull(someDependency);
    }
}

项目编译并且测试通过没有任何问题,即自动装配 SomeClass (“真实”对象)和 SomeDependency (由EasyMock生成的模拟对象)成功。

但是,如果我将 SomeClass 的实现更改为:

@Component
public class SomeClass {

    @Autowired
    SomeDependency someDependency;
}

两个测试都失败了,因为

Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [com.example.SomeDependency] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}

所以我的问题是:

  1. 为什么Spring无法将依赖关系自动装配到 SomeClass (当它成功将相同的依赖关系自动装配到 SomeClassTest 时)?
  2. 如何更改 SomeClassTest testconfig.xml 以使测试通过?
  3. 评论:实际上,由 SomeClass 表示的类是框架的一部分。因此,它不容易更新,至少不能在合理的时间内更新。

    依赖关系:

    • Spring:3.0.5.RELEASE
    • EasyMock:3.0

    修改

    从Spring 3.2 RC1开始,通用工厂方法和模拟对象的问题一直是solved

    / Mattias

1 个答案:

答案 0 :(得分:21)

在使用工厂创建具有自动装配的bean时,xml中的定义顺序似乎很重要。如果您将someInterfaceMock的声明置于component-scan之上,那么它将起作用。

一些澄清原因:当Spring尝试自动装配SomeClass时,它会搜索SomeDependency类型的bean。在此阶段someInterfaceMock仍然是工厂,因此Spring检查返回EasyMock.createMock(...)的工厂方法<T>的签名,以便Spring只找到Object,而不是所需的类型

更好的方法是使用Spring的FactoryBean界面来创建你的模拟。

这是一个应该有效的基本实现:

public class EasyMockFactoryBean<T> implements FactoryBean<T> {
    private Class<T> mockedClass;

    public void setMockedClass(Class mockedClass) {
        this.mockedClass = mockedClass;
    } 

    public T getObject() throws Exception {
        return EasyMock.createMock(mockedClass);
    }

    public Class<T> getObjectType() {
        return mockedClass;
    }

    public boolean isSingleton() {
        return true;
    } 

}

这是bean定义(顺序无关紧要!):

<bean class="com.example.EasyMockFactoryBean">
    <property name="mockedClass" value="com.example.Dependancy"/>
</bean>