我想将Mockito模拟对象注入到Spring (3+) bean中,以便使用JUnit进行单元测试。我的bean依赖项目前是通过在私有成员字段上使用@Autowired注释注入的。
我考虑过使用ReflectionTestUtils。setField,但是我希望注入的bean实例实际上是一个代理,因此没有声明目标类的私有成员字段。我不希望为依赖项创建公共setter,因为我将纯粹为了测试目的而修改我的接口。
我遵循了Spring社区提供的一些建议,但模拟没有被创建,自动连接失败:
<bean id="dao" class="org.mockito.Mockito" factory-method="mock">
<constructor-arg value="com.package.Dao" />
</bean>
我目前遇到的错误如下:
...
Caused by: org...NoSuchBeanDefinitionException:
No matching bean of type [com.package.Dao] found for dependency:
expected at least 1 bean which qualifies as autowire candidate for this dependency.
Dependency annotations: {
@org...Autowired(required=true),
@org...Qualifier(value=dao)
}
at org...DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(D...y.java:901)
at org...DefaultListableBeanFactory.doResolveDependency(D...y.java:770)
如果我将constructor-arg值设置为无效的值,那么在启动应用程序上下文时就不会出现错误。
更新:现在有更好、更清洁的解决方案来解决这个问题。请先考虑其他答案。
我最终在ronen的博客上找到了答案。我遇到的问题是由于Mockito方法。mock(类c)声明Object的返回类型。因此,Spring无法从工厂方法返回类型推断出bean类型。
Ronen的解决方案是创建一个返回模拟的FactoryBean实现。FactoryBean接口允许Spring查询工厂bean创建的对象类型。
我的模拟bean定义现在看起来如下:
<bean id="mockDaoFactory" name="dao" class="com.package.test.MocksFactory">
<property name="type" value="com.package.Dao" />
</bean>
考虑到:
@Service
public class MyService {
@Autowired
private MyDAO myDAO;
// etc
}
您可以通过自动装配加载被测试的类,使用Mockito模拟依赖项,然后使用Spring的ReflectionTestUtils将模拟注入到被测试的类中。
@ContextConfiguration(classes = { MvcConfiguration.class })
@RunWith(SpringJUnit4ClassRunner.class)
public class MyServiceTest {
@Autowired
private MyService myService;
private MyDAO myDAOMock;
@Before
public void before() {
myDAOMock = Mockito.mock(MyDAO.class);
ReflectionTestUtils.setField(myService, "myDAO", myDAOMock);
}
// etc
}
请注意,在Spring 4.3.1之前,此方法不适用于代理后面的服务(例如用@Transactional或Cacheable注释)。sprr -14050已经修复了这个问题。
对于早期版本,一种解决方案是打开代理,如文中所述:事务性注释避免模拟服务(这就是ReflectionTestUtils。setField现在默认执行)