简体   繁体   English

春季配置-注入模拟豆

[英]Spring Configuration - Inject Mock Beans

I am using Spring, Junit and Mockito. 我正在使用Spring,Junit和Mockito。 I need to override beans defined in the main spring configuration using another mockito test configuration (injecting mock beans only as needed). 我需要使用另一个Mockito测试配置覆盖主Spring配置中定义的bean(仅根据需要注入模拟bean)。 Nested beans have been @Autowired in the application. 嵌套bean已在应用程序中@Autowired

Update: 更新:
Based on alfcope 's answer below, it is important to add the name attribute so that spring can allow the primary bean (mock) to override the original one. 根据以下alfcope的回答,添加name属性很重要,这样spring才能允许主bean(模拟)覆盖原始bean。 Otherwise you get this exception: 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); 否则,您将收到以下异常: 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); 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);

The info message in the spring log shows: 春季日志中的信息消息显示:
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.

Example: 例:
I have a simplified example below that works. 我在下面有一个简化的示例可以工作。 Here, Bar is the nested inside Foo, and I need to mock Bar for testing: 在这里,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;
    }
}

Now for testing, let's say I want to inject a mockbar instead of the real bar. 现在进行测试,假设我要注入一个模拟栏,而不是真实的栏。 How can I achieve this in my test class below? 如何在下面的测试课程中实现这一目标?

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

Actual test case: 实际测试用例:

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

Based on the ConfigurationClassBeanDefinitionReader code I guess you are using xml configuration to define your main bean. 基于ConfigurationClassBeanDefinitionReader代码,我想您正在使用xml配置定义主bean。 If so, just add a name when creating your mockito bean. 如果是这样,只需在创建您的Mockito bean时添加一个名称。

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

This way Spring will allow you to have both beans, and as you are using @Primary it will be the one used by your tests. 这样,Spring将允许您同时拥有两个bean,并且在使用@Primary ,它将成为您的测试所使用的一个。

Spring overriding primary bean with non-primary bean 用非主bean春季覆盖主bean

ConfigurationClassBeanDefinitionReader Code ConfigurationClassBeanDefinitionReader代码

Alternatively, if you use Mockito, you can do this and completely do away with the extra MockitoTestConfiguration class and named primary mock beans in the test profile. 另外,如果您使用Mockito,则可以执行此操作,并完全消除测试配置文件中多余的MockitoTestConfiguration类和命名的主模拟bean。 Just simply do this: 只需执行以下操作:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM