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


当前回答

如果你正在使用spring boot 2.2+,你可以使用@MockInBean作为@MockBean的替代,并保持spring上下文干净:

@SpringBootTest
public class MyServiceTest {

    @MockInBean(MyService.class)
    private ServiceToMock serviceToMock;

    @Autowired
    private MyService myService;

    @Test
    public void test() {
        Mockito.when(serviceToMock.returnSomething()).thenReturn(new Object());
        myService.doSomething();
    }
}

免责声明:我创建这个库是为了避免由@MockBean/@SpringBean导致的Spring上下文重新创建,从而导致构建测试阶段变慢(参见在测试中使用@MockBean强制重新加载应用程序上下文或@MockBean的问题)

其他回答

<bean id="mockDaoFactory" name="dao" class="com.package.test.MocksFactory">
    <property name="type" value="com.package.Dao" />
</bean>

如果在XML文件的第一个/早期声明,这个^工作得很好。Mockito 1.9.0/Spring 3.0.5

最好的方法是:

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

更新 在上下文文件中,这个mock必须在任何自动连接字段(取决于它的声明)之前列出。

看看springingckito的开发速度和开放问题的数量,我现在有点担心把它引入我的测试套件堆栈。事实上,上一个版本是在Spring 4发布之前发布的,这带来了一些问题,比如“是否可以轻松地将它与Spring 4集成?”我不知道,因为我没试过。如果我需要在集成测试中模拟Spring bean,我更喜欢纯Spring方法。

有一个选项可以使用简单的Spring特性来伪造Spring bean。你需要使用@Primary, @Profile和@ActiveProfiles注解。我就这个话题写了一篇博客。

如果您正在使用spring >= 3.0,请尝试使用spring @Configuration注释来定义应用程序上下文的一部分

@Configuration
@ImportResource("com/blah/blurk/rest-of-config.xml")
public class DaoTestConfiguration {

    @Bean
    public ApplicationService applicationService() {
        return mock(ApplicationService.class);
    }

}

如果你不想使用@ImportResource,也可以用另一种方式:

<beans>
    <!-- rest of your config -->

    <!-- the container recognize this as a Configuration and adds it's beans 
         to the container -->
    <bean class="com.package.DaoTestConfiguration"/>
</beans>

有关更多信息,请参阅spring-framework-reference:基于java的容器配置

我找到了一个与teabot类似的答案,以创建一个提供模拟的MockFactory。我使用下面的例子来创建模拟工厂(因为到narkisr的链接是死的): http://hg.randompage.org/java/src/407e78aa08a0/projects/bookmarking/backend/spring/src/test/java/org/randompage/bookmarking/backend/testUtils/MocksFactory.java

<bean id="someFacade" class="nl.package.test.MockFactory">
    <property name="type" value="nl.package.someFacade"/>
</bean>

这也有助于防止Spring想要解析来自模拟bean的注入。