弹簧配置 - 注入模拟豆

时间:2017-06-22 20:44:34

标签: spring junit mockito

我正在使用Spring,Junit和Mockito。我需要使用另一个mockito测试配置覆盖主弹簧配置中定义的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);

春季日志中的信息消息显示:
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;
    }
}

现在进行测试,让我们说我想注入一个mockbar而不是真正的bar。我怎样才能在下面的测试课中实现这一目标?

@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);
    }
}

实际测试用例:

@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);
    }
}

2 个答案:

答案 0 :(得分:2)

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

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

这样Spring就可以让你拥有这两个bean,当你使用@Primary时,它将是你的测试使用的那个。

Spring overriding primary bean with non-primary bean

ConfigurationClassBeanDefinitionReader Code

答案 1 :(得分:0)

或者,如果您使用Mockito,您可以执行此操作并完全取消额外的MockitoTestConfiguration类并在测试配置文件中命名主模拟bean。只需这样做:

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

public class FooTest {

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

    @Before
    public void setUp() throws Exception {
        MockitoAnnotations.initMocks(this);
    }

    @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);
    }
}