是否可以使用 Spring ApplicationContext 中的 bean 参数化 JUnit Jupiter 测试?

Posted

技术标签:

【中文标题】是否可以使用 Spring ApplicationContext 中的 bean 参数化 JUnit Jupiter 测试?【英文标题】:Is it possible to parameterize a JUnit Jupiter test with beans from a Spring ApplicationContext? 【发布时间】:2019-06-26 06:58:15 【问题描述】:

我想编写一个针对给定类型的每个 Spring bean 执行的单元测试。 JUnit5 的参数化测试提供了很多可能性,但我不知道如何将 bean 注入方法源,因为它必须是静态方法。

有没有办法根据 Spring 的应用上下文确定 JUnit5 测试的参数?

【问题讨论】:

您可以只注入上下文并使用 Spring Bean 的名称作为参数并在某种设置代码中进行查找。 但是bean名称必须是静态列表? 【参考方案1】:

对于初学者,通过@MethodSource 配置的工厂方法不必是static。 User Guide 中的第二句解释了这一点。

测试类中的工厂方法必须是static,除非测试类使用@TestInstance(Lifecycle.PER_CLASS)注解;而外部类中的工厂方法必须始终为static

因此,如果您使用@TestInstance(PER_CLASS) 语义,您的@MethodSource 工厂方法可以是非静态的,因此可以访问注入到测试实例中的ApplicationContext

这是一个示例,它演示了 String 类型的 bean,bar bean 的故意失败。

import java.util.stream.Stream;

import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS;

@SpringJUnitConfig
@TestInstance(PER_CLASS)
class SpringBeansParameterizedTests 

    @Autowired
    ApplicationContext applicationContext;

    @ParameterizedTest
    @MethodSource
    void stringBeans(String bean) 
        assertEquals(3, bean.length());
    

    Stream<String> stringBeans() 
        return applicationContext.getBeansOfType(String.class).values().stream();
    

    @Configuration
    static class Config 

        @Bean
        String foo() 
            return "foo";
        

        @Bean
        String bar() 
            return "barf";
        
    

如果您不想直接使用ApplicationContext,您可以通过直接注入给定类型(本例中为String)的所有此类bean 的集合来简化解决方案,如下所示。

@SpringJUnitConfig
@TestInstance(PER_CLASS)
class SpringBeansParameterizedTests 

    @Autowired
    List<String> stringBeans;

    @ParameterizedTest
    @MethodSource
    void stringBeans(String bean) 
        assertEquals(3, bean.length());
    

    Stream<String> stringBeans() 
        return this.stringBeans.stream();
    

    @Configuration
    static class Config 

        @Bean
        String foo() 
            return "foo";
        

        @Bean
        String bar() 
            return "barf";
        
    

【讨论】:

【参考方案2】:

@TestFactory 的使用可能会有所帮助。

实际上,我偶然发现了一篇与您在 github 上所做的非常相似(或相同)的事情。

让您的测试使用SpringExtenion 运行,并使用注入的 Bean 作为我们测试的参数。

【讨论】:

以上是关于是否可以使用 Spring ApplicationContext 中的 bean 参数化 JUnit Jupiter 测试?的主要内容,如果未能解决你的问题,请参考以下文章

Spring Boot:是不是可以在带有胖 jar 的任意目录中使用外部 application.properties 文件?

Spring Boot - 从 Application.properties 填充列表/集合?

Spring application.properties 文件中的布尔值?

如何在spring-boot中添加多个application.properties文件?

如何在 Spring Boot 的 application.yml 中配置滚动文件附加程序

无法集成测试 gradle 多模块 Spring-Boot-Application