问题
I have a Spring 3.1/Java/Tomcat application. I have a service class that is as follows:
public class SomeServiceImpl implements SomeService {
@Autowired
public AnotherService anotherService;
// other code...
This uses another service class AnotherService which is autowired. Both these services classes are declared in a serviceContext.xml file.
I am writing junit to test SomeServiceImpl and use autowired to inject the class under test (SomeService) as well as the mock (EasyMock) dependency required by class under test (AnotherService). The easymock dependency for AnotherService is defined in a testContext.xml like below:
<bean id="mockAnotherService" class="org.easymock.EasyMock" factory-method="createMock" primary="true">
<constructor-arg value="com.xyz.AnotherService" />
</bean>
In my test class I configure to use both the context files. However, I am seeing that the ServiceImpl is correctly wired to the actual implementation (this is desired) but instead of mock version of AnotherService the concreate version (AnotherServiceImpl) is getting wired.
How do I get the mocked version of my dependency wired instead? I can not use @Resource or @Qualifier in the actual implementation as that would defeat the purpose. I am ok to use these in my test class.
回答1:
If they're both declared in serviceContext.xml
, and you want to mock one of them, then that file is no use for testing. Either split it so that you can use one of the 'real' Spring context files combined with a test context containing the mocks, or just create the bean manually and set the AnotherService
using a setter method. One of the advantages of Inversion of Control is to allow you to create beans by hand and inject the dependencies that way.
回答2:
Instead of configuring to use both context file can you import your serviceContext.xml into the testContext.xml and then only refer the textContext.xml in your test case.
When you import a configuration file into another file the other file gets an opportunity to override the bean definition in the imported file.
Make sure the id of the mock is same as your class - otherwise it will create two different beans. Another issue is that the mock object doesn't advertise the correct interface type - so autowiring by type might fail. To get around that issue you would need to do something like the following. I am using this approach with mockito - should work for easy mock as well.
<bean id="anotherService" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target">
<bean class="org.easymock.EasyMock" factory-method="createMock" primary="true">
<constructor-arg value="com.xyz.AnotherService" />
</bean>
</property>
<property name="proxyInterfaces">
<value>com.xyz.AnotherService</value>
</property>
</bean>
Another thing to try would be to create Java Config style methods in your class that create mock objects. If creating this directly in the test class doesn't work you can have another class with @Configuration with the method to create the mock and then define that as a bean in your testContext.xml
@Bean
AnotherService anotherService() {
return EasyMock.createMock(AnotherService.class);
}
来源:https://stackoverflow.com/questions/10553815/autowiring-beans-implementing-same-interface-how-to-autowire-a-particular-depe