EasyMock工厂方法生成的bean的自动装配?
我有一个对我来说似乎很奇怪的问题。我有以下设置:
一个接口:
package com.example;
public interface SomeDependency {
}
一个 spring 组件:
package com.example;
@Component
public class SomeClass {
}
一个带有 EasyMock 生成的模拟 bean 的 spring 测试配置:
<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< /em> (“真实”对象)和 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)}
所以我的问题是:
- 为什么 Spring 无法将依赖项自动装配到 SomeClass (当它成功自动装配对 SomeClassTest 具有相同的依赖性)?
- 如何更改 SomeClassTest 或 testconfig.xml 以使测试通过?
评论:实际上,SomeClass 表示的类是框架的一部分。因此,它不能轻易更新,至少不能在合理的时间内更新。
依赖项:
- Spring:3.0.5.RELEASE
- EasyMock:3.0
编辑:
从 Spring 3.2 RC1 开始,通用工厂方法和模拟对象的问题已经已解决。
/马蒂亚斯
I have a problem that seems really strange to me. I have the following setup:
An interface:
package com.example;
public interface SomeDependency {
}
A spring component:
package com.example;
@Component
public class SomeClass {
}
A spring test config with a mocked bean generated by EasyMock:
<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>
And a unit test:
@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);
}
}
The project compiles and the tests pass without any problem, i.e. autowiring of both SomeClass (a "real" object) and SomeDependency (a mock object generated by EasyMock) succeed.
However, if I change the implementation of SomeClass to:
@Component
public class SomeClass {
@Autowired
SomeDependency someDependency;
}
both tests fail because
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)}
So my questions are:
- Why does Spring fail to autowire the dependency to SomeClass (when it succeeds autowiring the same dependency to SomeClassTest)?
- How can I change the SomeClassTest or testconfig.xml to make the tests pass?
Comment: In reality the class represented by SomeClass is part of a framework. Consequently, it cannot easily be updated, at least not within reasonable time.
Dependencies:
- Spring: 3.0.5.RELEASE
- EasyMock: 3.0
Edit:
As of Spring 3.2 RC1, the problem with generic factory methods and mock objects has been solved.
/Mattias
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
当使用工厂通过自动装配创建 bean 时,xml 中定义的顺序实际上很重要。如果将
someInterfaceMock
声明放在component-scan
之上,它将起作用。一些澄清原因:当 Spring 尝试自动装配所以 Spring 只找到一个不是所需类型的
SomeClass
时,它会搜索SomeDependency
类型的 bean。在此阶段someInterfaceMock
仍然是一个工厂,因此 Spring 检查工厂方法EasyMock.createMock(...)
的签名,该方法返回Object
。更好的方法是使用 Spring 的
FactoryBean
接口来创建模拟。这是一个应该可以工作的基本实现:
这是 bean 定义(顺序并不重要!):
It seems the order of the definitions in the xml actually matter when using factories to create beans with autowiring. If you place the declaration of
someInterfaceMock
abovecomponent-scan
it will work.Some clarification why: When Spring tries to autowire
SomeClass
it searches for a bean of typeSomeDependency
. At this stagesomeInterfaceMock
is still a factory so Spring checks the signature of the factory methodEasyMock.createMock(...)
which returns<T>
so Spring only finds anObject
which isn't the type required.A better way would be to use Spring's
FactoryBean
interface to create your mocks.Here is a basic implementation that should work:
Here is the bean definition (the order won't matter!):