我想将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值设置为无效的值,那么在启动应用程序上下文时就不会出现错误。


当前回答

今天,我发现在Mockito bean之前声明的spring上下文无法加载。 移动After模拟后,应用程序上下文被成功加载。 保重:)

其他回答

从Spring 3.2开始,这不再是一个问题。Spring现在支持通用工厂方法结果的自动装配。请参阅本博客文章中“通用工厂方法”一节:http://spring.io/blog/2012/11/07/spring-framework-3-2-rc1-new-testing-features/。

重点是:

在Spring 3.2中,工厂方法的泛型返回类型现在是 正确地推断,并按类型自动装配模拟应该工作为 预期。因此,自定义变通方法,如 MockitoFactoryBean、EasyMockFactoryBean或springckito可能不是 不再必要。

这意味着这应该是开箱即用的:

<bean id="dao" class="org.mockito.Mockito" factory-method="mock">
    <constructor-arg value="com.package.Dao" />
</bean>

我根据Kresimir Nesek的建议开发了一个解决方案。我添加了一个新的注释@EnableMockedBean,以使代码更加清晰和模块化。

@EnableMockedBean
@SpringBootApplication
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes=MockedBeanTest.class)
public class MockedBeanTest {

    @MockedBean
    private HelloWorldService helloWorldService;

    @Autowired
    private MiddleComponent middleComponent;

    @Test
    public void helloWorldIsCalledOnlyOnce() {

        middleComponent.getHelloMessage();

        // THEN HelloWorldService is called only once
        verify(helloWorldService, times(1)).getHelloMessage();
    }

}

我已经写了一篇文章来解释它。

自从1.8.3 Mockito有了@InjectMocks——这是非常有用的。我的JUnit测试是@RunWith MockitoJUnitRunner,我构建了@Mock对象,它满足被测试类的所有依赖关系,当私有成员被@InjectMocks注释时,这些依赖关系都被注入。

我现在只使用SpringJUnit4Runner进行集成测试。

我将注意到,它似乎不能以与Spring相同的方式注入List<T>。它只寻找满足List的Mock对象,而不会注入Mock对象列表。我的解决方法是对一个手动实例化的列表使用@Spy,并手动将模拟对象添加到该列表中进行单元测试。也许这是故意的,因为它确实迫使我密切关注被嘲笑的是什么。

我建议将您的项目迁移到Spring Boot 1.4。之后,您可以使用新的注释@MockBean来伪造com.package.Dao

也许不是完美的解决方案,但我倾向于不使用spring来进行单元测试的DI。单个bean(被测试的类)的依赖关系通常不会太复杂,所以我只是直接在测试代码中进行注入。