在单元测试中覆盖自动装配的 Bean

Overriding an Autowired Bean in Unit Tests

有没有一种简单的方法可以在特定的单元测试中轻松覆盖自动装配的 bean?编译 类 中每种类型只有一个 bean,因此在这种情况下自动装配不是问题。测试 类 将包含额外的模拟。当 运行 一个单元测试时,我只想指定一个附加的配置,基本上说,而 运行 这个单元测试使用这个模拟而不是标准 bean。

配置文件对于我的要求来说似乎有点矫枉过正,我不确定这是否可以通过主要注释实现,因为不同的单元测试可能有不同的模拟。

您应该使用 spring 配置文件来了解您想要在不同的上下文中使用哪种 bean。

http://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-profiles.html

如果您只是想在测试中提供不同的 bean,我认为您不需要使用 spring 配置文件或 mockito。

只需执行以下操作:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = { TestConfig.class })
public class MyTest
{
    @Configuration
    @Import(Application.class) // the actual configuration
    public static class TestConfig
    {
        @Bean
        public IMyService myService()
        {
            return new MockedMyService();
        }
    }

    @Test
    public void test()
    {
        ....
    }
}

注意:使用 spring boot 1.3.2 / spring 4.2.4

测试

在 Spring Boot 1.4 中有一个简单的方法可以做到这一点:

@RunWith(SpringRunner.class)
@SpringBootTest(classes = { MyApplication.class })
public class MyTests {
    @MockBean
    private MyBeanClass myTestBean;

    @Before
    public void setup() {
         ...
         when(myTestBean.doSomething()).thenReturn(someResult);
    }

    @Test
    public void test() {
         // MyBeanClass bean is replaced with myTestBean in the ApplicationContext here
    }
}

我遇到了类似的问题,我混合解决了这个问题,我发现这个问题更有用且可重用。我为测试创建了一个 spring 配置文件和一个配置 class,它以一种非常简单的方式覆盖了我想模拟的 bean:

@Profile("test")
@Configuration
@Import(ApplicationConfiguration.class)
public class ConfigurationTests {

    @MockBean
    private Producer kafkaProducer;

    @MockBean
    private SlackNotifier slackNotifier;

}

通过这样做,我可以@Autowire 那些模拟 bean 并使用 mockito 来验证它们。主要优点是现在所有测试都无缝地获取模拟 bean,而无需对每个测试进行任何更改。 测试:

spring boot 1.4.2

正如 mats.nowak 评论的那样,@ContextConfiguration 对此很有用。

假设家长测试 class 就像:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:spring/some-dao-stuff.xml"
    ,"classpath:spring/some-rest-stuff.xml"
    ,"classpath:spring/some-common-stuff.xml"
    ,"classpath:spring/some-aop-stuff.xml"
    ,"classpath:spring/some-logging-stuff.xml"
    ,"classpath:spring/some-services-etc.xml"
})
public class MyCompaniesBigTestSpringConfig {
...

创建子测试class:

package x.y.z;
@ContextConfiguration
public class MyOneOffTest extends MyCompaniesBigTestSpringConfig {
...

并输入 src/test/resources/x/y/z/MyOneOffTest-context.xml

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
                           http://www.springframework.org/schema/context
                           http://www.springframework.org/schema/context/spring-context-3.0.xsd">


    <bean id="widgetsService" class="com.mycompany.mydept.myservice.WidgetsService" primary="true" />

</beans>

widgetsService bean 将覆盖(取代)主配置 xml(或 Java 配置)中定义的 bean。查看 inheritLocations 另请注意默认的 -context.xml 文件。 here 的例子。 更新:我必须添加 primary="true",显然这是需要的。

自 Spring Boot 1.4.0 而不是显式指定 @Configuration 进行测试,只需添加带有 @TestConfiguration 注释的静态嵌套 class 并提供替换 @Bean 注释为 @Primary.

@TestConfiguration 将被添加到您的主要 Spring 引导测试上下文(这意味着您的生产 bean 仍将被创建),但是来自 @TestConfiguration 的那个将被使用,因为@Primary.