我有一个对我来说真的很奇怪的问题。我有以下设置:
界面:
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)}
所以我的问题是:
评论:实际上,由 SomeClass 表示的类是框架的一部分。因此,它不容易更新,至少不能在合理的时间内更新。
依赖关系:
修改
从Spring 3.2 RC1开始,通用工厂方法和模拟对象的问题一直是solved。
/ Mattias
答案 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>