将模拟注入 bean 失败
对于我的单元测试,我想对被测 bean 的一些自动装配依赖项使用模拟。模拟已创建并正确注入到单元测试类中,但将其注入到被测 bean 中失败了,
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException:
No matching bean of type [Service] 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)}
这是我使用的 testContext.xml
<bean id="Service" class="org.easymock.EasyMock" factory-method="createMock">
<constructor-arg value="Service" ></constructor-arg>
</bean>
<bean id="Controller" class="Controller">
<property name="Service" ref="Service"></property>
</bean>
这是被测 bean (Controller.java) 的部分,其中接线失败
@Autowired
private Service service;
但是如果我将相同的模拟自动连接到我的单元测试类(ControllerTest.java)中,则不会发生错误,
@Autowired
private Service service;
注入的对象属于类型有
($Proxy18) EasyMock for interface Service
什么建议吗?为什么无法注入被测bean但注入测试有效?
亲切的问候 多米尼克
For my unit tests, I want to use mocks for some autowired dependencies of the bean under test. The mock is created and injected into the unit test class properly, but injecting it into the bean under test failed with
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException:
No matching bean of type [Service] 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)}
This is my used testContext.xml
<bean id="Service" class="org.easymock.EasyMock" factory-method="createMock">
<constructor-arg value="Service" ></constructor-arg>
</bean>
<bean id="Controller" class="Controller">
<property name="Service" ref="Service"></property>
</bean>
This is the part of the bean under test (Controller.java) where the wiring went fail
@Autowired
private Service service;
But if I autowire the same mock into my unit test class (ControllerTest.java), no error occured,
@Autowired
private Service service;
The injected object is of type
($Proxy18) EasyMock for interface Service
Any suggestion why the injection into the bean under test isn't possible but the injection into the test works ?
Kind regards
Dominik
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我认为这个问题可能与事情的顺序有关。在 ControllerTest 中,我猜您正在扩展 AbstractJUnit4SpringContextTests 或类似的东西首先连接所有的bean(在你有机会创建模拟之前)。如果没有看到整个类(或者至少是类声明、setUp、tearDown 和特定的测试方法),就很难说。
单元测试(与集成测试相反)的通常做法是根本不使用 spring 来连接任何东西 - 只需使用属性设置器手动注入模拟协作者。集成测试通常不使用模拟 - 它们使用真实的对象。
有时,您想要进行集成测试,但您想要模拟某个特定的协作者,因为真正的协作者会执行一些破坏性操作或发送短信或其他操作。在这些情况下我所做的就是让 Spring 按照它想要的方式连接所有内容,然后在所有内容都初始化后使用类中的属性设置器手动注入模拟。除非您想要模拟的真实类在初始化时做了您真正不想要的事情,否则没有问题。
I think the issue might have to do with the order of things. In ControllerTest, I'm guessing you are extending AbstractJUnit4SpringContextTests or something similar that is wiring up all of your beans first (before you even have a chance to create your mock). It's hard to say without seeing your whole class (or at least the class declaration, setUp, tearDown and particular test method).
The usual thing for unit tests (as opposed to integration tests) is to not use spring to wire anything up at all - just use the property setters to inject your mock collaborators manually. Integration tests don't normally use mocks - they use the real objects.
Occasionally, you want to do integration testing, but you want to mock one particular collaborator because the real one does something destructive or sends an SMS message or something. What I have done in those situations is to let Spring wire up everything the way it wants to and then manually inject the mock using the property setter in the class after everything is all initialized. Unless the real class that you want to mock does something in its initialization that you really don't want, there's no problem.
这可能与随机效应有关:Spring 的 bean 实例化顺序。
查看您的应用程序上下文配置片段,spring 无法知道它必须首先创建 Service 类型的模拟对象,因为它不知道 id Service 的 bean 实例化将导致 Service 类型。如果首先创建控制器 bean,这可能会阻止自动装配。
要确认这一点,请尝试
(编辑:您在 Service 的 xml 配置中使用自动装配和显式属性。如果从 Controller.Service 中删除 @Autowired 会发生什么?)
在引用 @jhericks 的旁注中,我们有时会注入模拟对象在集成测试中(在极少数情况下这是绝对必要的),应用程序有一个可选参数(命令行、配置文件等),我们可以在其中为其提供附加的 xml 应用程序上下文配置文档。这个简短的文档覆盖了相关 bean 的 bean 声明,并将其替换为模拟变体。
Possibly this has to do with a random effect: Spring's bean instantiation order.
Looking at your application context configuration fragment, spring has no way to know that it has to create the mock object of type Service first because it does not know that the instantiation of the bean with id Service will result in type Service. This may prevent autowiring if the Controller bean is created first.
To confirm this, try
(EDIT: You use autowiring AND an explicit property in the xml config for Service. What happens if you delete the @Autowired from Controller.Service?)
On a side note referring to @jhericks, we sometimes inject mock objects in integrations tests (in the rare cases where this is absolutely neccessary) this way: The application has an optional parameter (command line, config file or so) where we can supply it with an additional xml application context configuration document. This short document overrides the bean declaration for the bean in question, replacing it with the mock variant.