Spring 配置 - 注入 Mock Bean

cod*_*kix 4 junit spring mockito

我正在使用 Spring、Junit 和 Mockito。我需要使用另一个mockito测试配置来覆盖主spring配置中定义的bean(仅根据需要注入模拟bean)。嵌套bean已经@Autowired在应用程序中。

更新:
根据下面alfcope的答案,添加该name属性非常重要,以便 spring 可以允许主 bean(模拟)覆盖原始 bean。否则你会得到这个异常: org.mockito.exceptions.misusing.MissingMethodInvocationException: when() requires an argument which has to be 'a method call on a mock'. For example: when(mock.getArticles()).thenReturn(articles);

spring 日志中的信息消息显示:
Skipping bean definition for [BeanMethod:name=bar,declaringClass=test.package.MockitoTestConfiguration]: a definition for bean 'bar' already exists. This top-level bean definition is considered as an override.

示例:
我下面有一个可行的简化示例。这里,Bar是嵌套在Foo内部的,我需要模拟Bar进行测试:

@Component
public class Foo
{
    @Autowired
    private Bar bar;

    public String getResponseFromBar(String request)
    {
        String response = bar.someMethod(String request);
        //do something else with this reponse
        return response;
    }

} 

@Component
public class Bar {
    public String someMethod(String request) {
        String response = null;
        //do something
        return response;
    }
}
Run Code Online (Sandbox Code Playgroud)

现在为了测试,假设我想注入一个模拟栏而不是真实的栏。我怎样才能在下面的测试类中实现这一目标?

@Profile("test")
@Configuration
public class MockitoTestConfiguration {

    //adding the name attribute is important.
    @Bean(name="mockBar")
    @Primary 
    public Bar bar() {
        logger.debug("injecting mock bar");
        return Mockito.mock(Bar.class);
    }
}
Run Code Online (Sandbox Code Playgroud)

实际测试用例:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath*:test-context.xml")

public class FooTest {

    @Autowired
    Foo foo;
    @Autowired
    Bar mockBar; //need this to set up the mock response in the test case.

    @Test
    public void testAMethodInFoo_WithBarInjectedByMockito() {

        //set up the mockBar response
        Mockito.when(mockBar.someMethod("1")).thenReturn("1-response");

        String response = foo.getResponseFromBar();
        assertEquals("1-response", response);
    }
}
Run Code Online (Sandbox Code Playgroud)

alf*_*ope 6

根据ConfigurationClassBeanDefinitionReader代码,我猜您正在使用 xml 配置来定义您的主 bean。如果是这样,只需在创建mockito bean 时添加一个名称即可。

@Bean(name="mockbar") 
@Primary 
public Bar bar() {
    logger.debug("injecting mock bar");
    return Mockito.mock(Bar.class);
}
Run Code Online (Sandbox Code Playgroud)

这样 Spring 将允许您拥有这两个 bean,并且当您使用它时@Primary,它将成为您的测试所使用的那个 bean。

Spring 用非主 bean 覆盖主 bean

ConfigurationClassBeanDefinitionReader 代码