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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/28605833/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-08 00:22:48  来源:igfitidea点击:

Overriding an Autowired Bean in Unit Tests

springspring-bootspring-annotations

提问by samblake

Is there a simple way I can easily override an autowired bean in specific unit tests? There is only a single bean of every type in the compile classes so it's not a problem for autowiring in this case. The test classes would contain additional mocks. When running a unit test I'd simply like to specify an additional Configuration that says basically, while running this unit test use this mock instead of the standard bean.

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

Profiles seem a bit overkill for what I require and I'm not sure this would be achievable with the Primary annotation as different unit test could have different mocks.

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

回答by teo

If you just simply want to provide a different bean in your tests, i think you don't need to use spring profiles or mockito.

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

Just do the following:

只需执行以下操作:

@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()
    {
        ....
    }
}

NOTE: tested with spring boot 1.3.2 / spring 4.2.4

注意:使用弹簧靴 1.3.2 / 弹簧 4.2.4 进行测试

回答by Sergey Shcherbakov

In Spring Boot 1.4 there's a simple way for doing that:

在 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
    }
}

回答by Israel Fernández

I had similar problem and I solved with a mix and I find this one more useful and reusable. I created a spring profile for the tests and a config class that overrides the beans I want to mock in a very simple way:

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

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

    @MockBean
    private Producer kafkaProducer;

    @MockBean
    private SlackNotifier slackNotifier;

}

By doing that I can @Autowire those mock beans and use mockito to verify on them. Main advantage is that now all tests seamlessly get the mock beans without any per-test change. Tested with:

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

spring boot 1.4.2

弹簧靴 1.4.2

回答by Eddú Meléndez

You should use spring profiles in order to know what kind of bean you want to use in different contexts.

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

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

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

回答by awgtek

As mats.nowak commented, @ContextConfigurationis useful for this.

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

Say a parent test class is like:

说一个父测试类是这样的:

@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 {
...

Create a child test class:

创建一个子测试类:

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

and put in src/test/resources/x/y/z/MyOneOffTest-context.xml

并放入 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>

That widgetsServicebean will override (take the place of) the bean defined in the main config xml (or Java config). See about inheritLocationsAlso Note the default -context.xml file. Example of that here. Update: I had to add primary="true", apparently it's needed.

widgetsServicebean 将覆盖(代替)在主配置 xml(或 Java 配置)中定义的 bean。请参阅inheritLocations另请注意默认的-context.xml 文件。这里的例子。更新:我不得不添加primary="true",显然是需要的。