天天看点

Spring 5 中文解析核心篇-集成测试之TestContext(中)

3.5.5 上下文管理

每个

TestContext

为其负责的测试实例提供上下文管理和缓存支持。测试实例不会自动接收对配置的

ApplicationContext

的访问。但是,如果测试类实现

ApplicationContextAware

接口,则将对

ApplicationContext

的引用提供给测试实例。请注意,

AbstractJUnit4SpringContextTests

AbstractTestNGSpringContextTests

实现了

ApplicationContextAware

,因此可以自动提供对

ApplicationContext

的访问。

@Autowired

ApplicationContext

作为实现

ApplicationContextAware

接口的替代方法,你可以通过字段或

setter

方法上的

@Autowired

注解为测试类注入应用程序上下文,如以下示例所示:
@SpringJUnitConfig
class MyTest {

 @Autowired //1
 ApplicationContext applicationContext;

 // class body...
}           
  1. 注入

    ApplicationContext

同样,如果将测试配置为加载

WebApplicationContext

,则可以将Web应用程序上下文注入到测试中,如下所示:
@SpringJUnitWebConfig //1
class MyWebAppTest {

    @Autowired //2
    WebApplicationContext wac;

    // class body...
}           
  1. 配置

    WebApplicationContext

  2. WebApplicationContext

使用

@Autowired

的依赖关系注入是

DependencyInjectionTestExecutionListener

提供的,它是默认配置的( 参见测试装置的依赖注入 )。

TestContext

框架的测试类不需要扩展任何特定的类或实现特定的接口来配置其应用程序上下文。而是通过在类级别声明

@ContextConfiguration

注解来实现配置。如果你的测试类未明确声明应用程序上下文资源位置或组件类,则配置的

ContextLoader

将确定如何从默认位置或默认配置类加载上下文。除了上下文资源位置和组件类之外,还可以通过应用程序上下文初始化程序配置应用程序上下文。

以下各节说明如何使用Spring的

@ContextConfiguration

注解通过XML配置文件、

Groovy

脚本、组件类(通常为

@Configuration

类)或上下文初始化器来配置测试

ApplicationContext

。另外,你可以为高级用例实现和配置自己的自定义

SmartContextLoader

若要使用XML配置文件为测试加载

ApplicationContext

,请使用

@ContextConfiguration

注解测试类,并使用包含XML配置元数据的资源位置的数组配置

locations

属性。简单路径或相对路径(例如

context.xml

)被视为相对于定义测试类的程序包的类路径资源。以斜杠开头的路径被视为绝对类路径位置(例如:

/org/example/config.xml

)。照原样使用表示资源URL的路径(即以

classpath:

file:

http:

等开头的路径)。

@ExtendWith(SpringExtension.class)
// ApplicationContext从根路径加载"/app-config.xml" 和
// "/test-config.xml"
@ContextConfiguration(locations={"/app-config.xml", "/test-config.xml"}) //1
class MyTest {
    // class body...
}           
  1. locations

    属性设置为XML文件列表。

@ContextConfiguration

通过标准Java值属性为

locations

属性支持别名。因此,如果不需要在

@ContextConfiguration

中声明其他属性,你可以使用以下示例中演示的格式,省略

locations

属性名称的声明并声明资源位置。

@ExtendWith(SpringExtension.class)
@ContextConfiguration({"/app-config.xml", "/test-config.xml"}) //1
class MyTest {
    // class body...
}           
  1. 不使用

    location

    属性指定XML文件。

如果你从

@ContextConfiguration

注解中省略了位置和值属性,则

TestContext

框架将尝试检测默认的XML资源位置。具体而言,

GenericXmlContextLoader

GenericXmlWebContextLoader

根据测试类的名称检测默认位置。如果你的类名为

com.example.MyTest

GenericXmlContextLoader

classpath:com/example/MyTest-context.xml

加载应用程序上下文。以下示例显示了如何执行此操作:

@ExtendWith(SpringExtension.class)
// ApplicationContext will be loaded from
// "classpath:com/example/MyTest-context.xml"
@ContextConfiguration //1
class MyTest {
    // class body...
}           
  1. 从默认位置加载配置。

要通过使用

Groovy Bean定义DSL

的Groovy脚本为测试加载

ApplicationContext

,可以使用

@ContextConfiguration

注解测试类,并使用包含Groovy脚本资源位置的数组配置

location

value

属性。Groovy脚本的资源查找语义与针对

XML配置文件

描述的语义相同。

激活Groovy脚本支持

如果类路径中有Groovy,那么就会自动启用使用Groovy脚本在Spring

TestContext

框架中加载

ApplicationContext

的支持。

下面的示例显示如何指定Groovy配置文件:

@ExtendWith(SpringExtension.class)
// ApplicationContext will be loaded from "/AppConfig.groovy" and
// "/TestConfig.groovy" in the root of the classpath
@ContextConfiguration({"/AppConfig.groovy", "/TestConfig.Groovy"}) 
class MyTest {
    // class body...
}           

@ContextConfiguration

注解中省略了

location

value

属性,则

TestContext

框架将尝试检测默认的Groovy脚本。具体来说,

GenericGroovyXmlContextLoader

GenericGroovyXmlWebContextLoader

com.example.MyTest

则Groovy上下文加载器将从

classpath:com/example/MyTestContext.groovy

加载应用程序上下文。下面的示例演示如何使用默认值:

@ExtendWith(SpringExtension.class)
// ApplicationContext will be loaded from
// "classpath:com/example/MyTestContext.groovy"
@ContextConfiguration //1
class MyTest {
    // class body...
}           

同时声明XML配置和Groovy脚本

你可以使用

@ContextConfiguration

location

value

属性同时声明XML配置文件和Groovy脚本。如果到配置的资源位置的路径以

.xml

结尾,则使用

XmlBeanDefinitionReader

加载该路径。否则,将使用

GroovyBeanDefinitionReader

加载它。

以下清单显示了如何在集成测试中将两者结合起来:

@ExtendWith(SpringExtension.class)
// ApplicationContext将从
// "/app-config.xml" 和 "/TestConfig.groovy"加载上下文
@ContextConfiguration({ "/app-config.xml", "/TestConfig.groovy" })
class MyTest {
 // class body...
}           

要使用组件类(请参见

基于Java的容器配置

)为测试加载

ApplicationContext

@ContextConfiguration

注解测试类,并使用包含对组件类的引用的数组来配置

classes

属性。以下示例显示了如何执行此操作:

@ExtendWith(SpringExtension.class)
// ApplicationContext将从AppConfig和TestConfig加载上下文
@ContextConfiguration(classes = {AppConfig.class, TestConfig.class}) //1
class MyTest {
    // class body...
}           
  1. 指定组件类。

组件类

术语

组件类

可以指以下任何一种:
  • @Configuration

    注解的类。
  • 组件(即,用

    @Component

    @Service

    @Repository

    或其他构造型注解注释的类)。
  • 与JSR-330兼容的类,该类使用

    javax.inject

    注解进行了注释。
  • 包含

    @Bean

    方法的任何类。
  • 打算注册为Spring组件的任何其他类(即

    ApplicationContext

    中的Spring bean),可能利用单个自动构造函数的自动装配而无需使用Spring注解。
有关组件类的配置和语义的更多信息,请参见 @Configuration @Bean 的javadoc,尤其要注意

@Bean

Lite模式的讨论。

@ContextConfiguration

classes

TestContext

框架将尝试检测默认配置类的存在。具体来说,

AnnotationConfigContextLoader

AnnotationConfigWebContextLoader

检测到满足配置类实现要求的测试类的所有静态嵌套类,如

javadoc中所指定。请注意,配置类的名称是任意的。另外,如果需要,一个测试类可以包含多个静态嵌套配制类。在以下示例中,

OrderServiceTest

类声明一个名为

Config

的静态嵌套配置类,该配置类将自动用于为测试类加载

ApplicationContext

@SpringJUnitConfig //1
// ApplicationContext将从内部潜逃静态累加载
class OrderServiceTest {

    @Configuration
    static class Config {

        // this bean will be injected into the OrderServiceTest class
        @Bean
        OrderService orderService() {
            OrderService orderService = new OrderServiceImpl();
            // set properties, etc.
            return orderService;
        }
    }

    @Autowired
    OrderService orderService;

    @Test
    void testOrderService() {
        // test the orderService
    }

}           
  1. 从嵌套的Config类加载配置信息。

有时可能需要混合使用XML配置文件、Groovy脚本和组件类(通常为

@Configuration

类)来为测试配置

ApplicationContext

。如果在生产中使用XML配置,则可以决定要使用

@Configuration

类为测试配置特定的Spring托管组件,反之亦然。

此外,某些第三方框架(例如Spring Boot)提供了一流的支持,可以同时从不同类型的资源(例如XML配置文件、Groovy脚本和

@Configuration

类)中加载

ApplicationContext

。过去,Spring框架不支持此标准部署。因此,Spring框架在

spring-test

模块中提供的大多数

SmartContextLoader

实现对于每个测试上下文仅支持一种资源类型。但是,这并不意味着你不能同时使用两者。通用规则的一个例外是

GenericGroovyXmlContextLoader

GenericGroovyXmlWebContextLoader

同时支持XML配置文件和Groovy脚本。此外,第三方框架可以选择通过

@ContextConfiguration

支持位置和类的声明,并且,借助

TestContext

框架中的标准测试支持,你可以选择以下选项。

如果要使用资源位置(例如XML或Groovy)和

@Configuration

类的配置测试,则必须选择一个作为入口点,并且其中一个必须包含或导入另一个。例如,在XML或Groovy脚本中,可以通过使用组件扫描或将它们定义为普通的Spring bean来包括

@Configuration

类,而在

@Configuration

类中,可以使用

@ImportResource

导入XML配置文件或Groovy脚本。请注意,此行为在语义上等同于你在生产环境中配置应用程序的方式:在生产配置中,你定义了一组XML或Groovy资源位置或一组

@Configuration

类,从中加载了生产

ApplicationContext

,但是你仍然包含或导入其他类型的配置的自由。

若要使用上下文初始化程序为你的测试配置

ApplicationContext

@ContextConfiguration

注解测试类,并使用包含对实现

ApplicationContextInitializer

的类的引用的数组配置初始化程序属性。然后,使用声明的上下文初始值设定项来初始化为测试加载的

ConfigurableApplicationContext

。请注意,每个声明的初始化程序支持的具体

ConfigurableApplicationContext

类型必须与使用中的

SmartContextLoader

创建的

ApplicationContext

类型(通常是

GenericApplicationContext

)兼容。此外,初始化程序的调用顺序取决于它们是实现Spring的

Ordered

接口还是以Spring的

@Order

注解或标准的

@Priority

注解进行注释。下面的示例演示如何使用初始化程序:

@ExtendWith(SpringExtension.class)
// ApplicationContext将从TestConfig
// 和 通过TestAppCtxInitializer初始化
@ContextConfiguration(
    classes = TestConfig.class,
    initializers = TestAppCtxInitializer.class) //1
class MyTest {
    // class body...
}           
  1. 使用配置类和初始化程序指定配置。

你还可以完全省略

@ContextConfiguration

中的XML配置文件、Groovy脚本或组件类的声明,而仅声明

ApplicationContextInitializer

类,然后这些类负责在上下文中注册Bean(例如,通过编程方式从XML文件加载Bean定义)或配置类。以下示例显示了如何执行此操作:

@ExtendWith(SpringExtension.class)
// ApplicationContext will be initialized by EntireAppInitializer
// which presumably registers beans in the context
@ContextConfiguration(initializers = EntireAppInitializer.class) //1
class MyTest {
    // class body...
}           
  1. 仅使用初始化程序来指定配置。
参考代码:

org.liyong.test.annotation.test.spring.ContextInitializerTests

@ContextConfiguration

支持

boolean

inheritLocations

inheritinitialalizer

属性,它们表示是否应该继承由超类声明的资源位置或组件类和上下文初始化器。这两个标志的默认值为

true

。这意味着测试类将继承资源位置或组件类以及任何超类申明的上下文初始化器。具体来说,将测试类的资源位置或组件类附加到由超类申明的资源位置或带注解的类的列表中。同样,将给定测试类的初始化程序添加到由测试超类定义的初始化程序集。因此,子类可以选择扩展资源位置、组件类或上下文初始化程序。

如果

@ContextConfiguration

中的

inheritLocations

inheritInitializers

属性被设置为

false

,则测试类的资源位置或组件类和上下文初始化器将分别有效地替代超类定义的配置。

在下一个使用XML资源位置的示例中,从

Base-config.xml

Extended-config.xml依

次加载

ExtendedContext

ApplicationContext

。因此,

extended-config.xml

中定义的Bean可以覆盖(即替换)

base-config.xml

中定义的那些。以下示例显示了一个类如何扩展另一个类并使用其自己的配置文件和超类的配置文件:

@ExtendWith(SpringExtension.class)
// ApplicationContext将从类路径根目录加载"/base-config.xml"
@ContextConfiguration("/base-config.xml") //1
class BaseTest {
    // class body...
}

// ApplicationContext将从类路径根目录加载"/base-config.xml" 和
// "/extended-config.xml"
@ContextConfiguration("/extended-config.xml") //2
class ExtendedTest extends BaseTest {
    // class body...
}           
  1. 在超类中定义的配置文件
  2. 子类中定义的配置文件。

同样,在下一个使用组件类的示例中,从

BaseConfig

ExtendedConfig

类按该顺序加载

ExtendedTest

ApplicationContext

。因此,在

ExtendedConfig

中定义的Bean可以覆盖(即替换)在

BaseConfig

中定义的Bean。下面的示例显示一个类如何扩展另一个类,并同时使用自己的配置类和超类的配置类:

// ApplicationContext从BaseConfig加载
@SpringJUnitConfig(BaseConfig.class) //1
class BaseTest {
    // class body...
}

// ApplicationContext将从BaseConfig和ExtendedConfig加载
@SpringJUnitConfig(ExtendedConfig.class) //2
class ExtendedTest extends BaseTest {
    // class body...
}           
  1. 在超类中定义的配置类
  2. 在子类中定义的配置类。

在使用上下文初始化程序的下一个示例中,通过使用

BaseInitializer

ExtendedInitializer

初始化

ExtendedTest

ApplicationContext

。但是请注意,初始化程序的调用顺序取决于它们是实现Spring的

Ordered

@Order

@Priority

注解进行注释。以下示例显示了一个类如何扩展另一个类并使用其自己的初始化程序和超类的初始化程序:

// ApplicationContext将通过BaseInitializer初始化
@SpringJUnitConfig(initializers = BaseInitializer.class) //1
class BaseTest {
    // class body...
}

// ApplicationContext将通过BaseInitializer
// 和 ExtendedInitializer初始化
@SpringJUnitConfig(initializers = ExtendedInitializer.class) //2
class ExtendedTest extends BaseTest {
    // class body...
}           
  1. 超类中定义的初始化器。
  2. 子类中定义的初始化程序。

使用环境配置文件进行上下文配置

Spring框架对环境和配置文件(又名“bean定义配置文件”)的概念提供了一流的支持,可以配置集成测试来激活针对各种测试场景的特定bean定义配置文件。这可以通过使用

@ActiveProfiles

注解测试类并提供在加载测试的

ApplicationContext

时应激活的配置文件列表来实现。

你可以将

@ActiveProfiles

SmartContextLoader

SPI的任何实现一起使用,但较早的

ContextLoader

SPI的实现不支持

@ActiveProfiles

考虑两个带有XML配置和

@Configuration

类的示例:

<!-- app-config.xml -->
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:jdbc="http://www.springframework.org/schema/jdbc"
    xmlns:jee="http://www.springframework.org/schema/jee"
    xsi:schemaLocation="...">

    <bean id="transferService"
            class="com.bank.service.internal.DefaultTransferService">
        <constructor-arg ref="accountRepository"/>
        <constructor-arg ref="feePolicy"/>
    </bean>

    <bean id="accountRepository"
            class="com.bank.repository.internal.JdbcAccountRepository">
        <constructor-arg ref="dataSource"/>
    </bean>

    <bean id="feePolicy"
        class="com.bank.service.internal.ZeroFeePolicy"/>

    <beans profile="dev">
        <jdbc:embedded-database id="dataSource">
            <jdbc:script
                location="classpath:com/bank/config/sql/schema.sql"/>
            <jdbc:script
                location="classpath:com/bank/config/sql/test-data.sql"/>
        </jdbc:embedded-database>
    </beans>

    <beans profile="production">
        <jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/datasource"/>
    </beans>

    <beans profile="default">
        <jdbc:embedded-database id="dataSource">
            <jdbc:script
                location="classpath:com/bank/config/sql/schema.sql"/>
        </jdbc:embedded-database>
    </beans>

</beans>           
@ExtendWith(SpringExtension.class)
// ApplicationContext will be loaded from "classpath:/app-config.xml"
@ContextConfiguration("/app-config.xml")
@ActiveProfiles("dev")
class TransferServiceTest {

    @Autowired
    TransferService transferService;

    @Test
    void testTransferService() {
        // test the transferService
    }
}           

运行

TransferServiceTest

时,会从类路径根目录中的

app-config.xml

配置文件中加载其

ApplicationContext

。如果检查

app-config.xml

,可以看到accountRepository bean对

dataSource

bean有依赖性。但是,

dataSource

未被定义为顶级bean。相反,

dataSource

定义了三次:在生产配置文件中、在开发配置文件中以及在默认配置文件中。

通过使用

@ActiveProfiles(“dev”)

注解

TransferServiceTest

,我们指示Spring

TestContext

框架加载具有设置为

{“dev”}

的激活配置文件的

ApplicationContext

。结果,创建了一个嵌入式数据库,并用测试数据填充了数据库,并用对开发

DataSource

的引用来连接

accountRepository

bean。这可能是我们在集成测试中想要的。

有时将bean分配给默认配置文件很有用。只有在没有特别激活其他配置文件时,才会包含缺省配置文件中的bean。你可以使用它来定义在应用程序的默认状态中使用的后备bean。例如,你可以显式提供

dev

production

的数据源,但是当两者都不处于活动状态时,将内存中数据源定义为默认值。

以下代码清单演示了如何使用

@Configuration

类而不是XML实现相同的配置和集成测试:

@Configuration
@Profile("dev")
public class StandaloneDataConfig {

    @Bean
    public DataSource dataSource() {
        return new EmbeddedDatabaseBuilder()
            .setType(EmbeddedDatabaseType.HSQL)
            .addScript("classpath:com/bank/config/sql/schema.sql")
            .addScript("classpath:com/bank/config/sql/test-data.sql")
            .build();
    }
}           
@Configuration
@Profile("production")
public class JndiDataConfig {

    @Bean(destroyMethod="")
    public DataSource dataSource() throws Exception {
        Context ctx = new InitialContext();
        return (DataSource) ctx.lookup("java:comp/env/jdbc/datasource");
    }
}           
@Configuration
@Profile("default")
public class DefaultDataConfig {

    @Bean
    public DataSource dataSource() {
        return new EmbeddedDatabaseBuilder()
            .setType(EmbeddedDatabaseType.HSQL)
            .addScript("classpath:com/bank/config/sql/schema.sql")
            .build();
    }
}           
@Configuration
public class TransferServiceConfig {

    @Autowired DataSource dataSource;

    @Bean
    public TransferService transferService() {
        return new DefaultTransferService(accountRepository(), feePolicy());
    }

    @Bean
    public AccountRepository accountRepository() {
        return new JdbcAccountRepository(dataSource);
    }

    @Bean
    public FeePolicy feePolicy() {
        return new ZeroFeePolicy();
    }
}           
@SpringJUnitConfig({
        TransferServiceConfig.class,
        StandaloneDataConfig.class,
        JndiDataConfig.class,
        DefaultDataConfig.class})
@ActiveProfiles("dev")
class TransferServiceTest {

    @Autowired
    TransferService transferService;

    @Test
    void testTransferService() {
        // test the transferService
    }
}           

在此变体中,我们将XML配置分为四个独立的

@Configuration

类:

  • ransferServiceConfig

    : 通过使用

    @Autowired

    进行依赖项注入来获取数据源。
  • StandaloneDataConfig

    : 为适合开发人员测试的嵌入式数据库定义数据源。
  • JndiDataConfig

    : 定义在生产环境中从JNDI检索的数据源。
  • DefaultDataConfig

    : 如果没有配置文件处于激活状态,则为默认的嵌入式数据库定义一个数据源。

与基于XML的配置示例一样,我们仍然使用

@ActiveProfiles("dev")

TransferServiceTest

,但是这次我们使用

@ContextConfiguration

注解指定所有四个配置类。测试类的主体本身保持完全不变。

在一个给定项目中,跨多个测试类使用一组配置文件是很常见的。因此,为避免

@ActiveProfiles

注解的重复声明,可以在基类中声明一次

@ActiveProfiles

,子类会自动从基类继承

@ActiveProfiles

配置。在以下示例中,

@ActiveProfiles

的声明(以及其他注解)已移至抽象超类

AbstractIntegrationTest

@SpringJUnitConfig({
        TransferServiceConfig.class,
        StandaloneDataConfig.class,
        JndiDataConfig.class,
        DefaultDataConfig.class})
@ActiveProfiles("dev")
abstract class AbstractIntegrationTest {
}           
// "dev"配置集成父类
class TransferServiceTest extends AbstractIntegrationTest {

    @Autowired
    TransferService transferService;

    @Test
    void testTransferService() {
        // test the transferService
    }
}           

@ActiveProfiles

还支持可用于禁用激活配置文件的继承的

InheritedProfiles

属性,如以下示例所示:

// "dev"配置被"production"覆盖
@ActiveProfiles(profiles = "production", inheritProfiles = false)
class ProductionTransferServiceTest extends AbstractIntegrationTest {
    // test body
}           

此外,有时有必要以编程方式而不是声明方式来解析测试的激活配置文件,例如,基于:

  • 当前的操作系统。
  • 是否在持续集成构建服务器上执行测试。
  • 存在某些环境变量。
  • 自定义类级别注释的存在。
  • 其他问题。

要以编程方式解析活动bean定义配置文件,可以实现自定义

ActiveProfilesResolver

并使用

@ActiveProfiles

resolver

属性对其进行注册。有关更多信息,请参见相应的

javadoc

。下面的示例演示如何实现和注册自定义的

OperatingSystemActiveProfilesResolver

// "dev"配置通过自定义解析器编程式地覆盖
@ActiveProfiles(
        resolver = OperatingSystemActiveProfilesResolver.class,
        inheritProfiles = false)
class TransferServiceTest extends AbstractIntegrationTest {
    // test body
}           
public class OperatingSystemActiveProfilesResolver implements ActiveProfilesResolver {

    @Override
    public String[] resolve(Class<?> testClass) {
        String profile = ...;
        // determine the value of profile based on the operating system
        return new String[] {profile};
    }
}           

Spring框架对具有属性源层次结构的环境概念提供了一流的支持,你可以使用特定于测试的属性源配置集成测试。与

@Configuration

类上使用的

@PropertySource

注解相反,可以在测试类上声明

@TestPropertySource

注解,以声明测试属性文件或内联属性的资源位置。这些测试属性源被添加到环境中为带注解的集成测试加载的

ApplicationContext

PropertySources

集合中。

@TestPropertySource

SmartContextLoader

SPI的任何实现一起使用,但是较早的

ContextLoader

@TestPropertySource

SmartContextLoader

的实现可通过

MergedContextConfiguration

getPropertySourceLocations()

getPropertySourceProperties()

方法访问合并的测试属性源值。

声明测试属性源

@TestPropertySource的location

value

属性来配置测试属性文件。

支持传统属性文件格式和基于XML的属性文件格式,例如:

classpath:/com/example/test.properties

file:///path/to/file.xml

每个路径都被解析为Spring资源。普通路径(例如

test.properties

)被视为相对于定义测试类的程序包的类路径资源。以斜杠开头的路径被视为绝对类路径资源(例如:

/org/example/test.xml

)。通过使用指定的资源协议加载引用URL的路径(例如,以

classpath:

file:

http:

为前缀的路径)。不允许使用资源位置通配符(例如

* /.properties

)每个位置都必须精确评估为一个

.properties

.xml

资源。

以下示例使用测试属性文件:

@ContextConfiguration
@TestPropertySource("/test.properties") //1
class MyIntegrationTests {
    // class body...
}           
  1. 指定具有绝对路径的属性文件。

@TestPropertySource

properties

属性,以键/值对的形式配置内联属性,如下例所示。所有键值对都作为优先级最高的单个测试

PropertySource

添加到封闭环境中。

键值对支持的语法与为Java属性文件中的条目定义的语法相同:

  • key=value

  • key:value

  • key value

下面的示例设置两个内联属性:

@ContextConfiguration
@TestPropertySource(properties = {"timezone = GMT", "port: 4242"}) //1
class MyIntegrationTests {
    // class body...
}
           
  1. 通过使用键值语法的两种变体来设置两个属性。
从Spring框架5.2开始,

@TestPropertySource

可以用作可重复注解。这意味着你可以在单个测试类上具有

@TestPropertySource

的多个声明,其后的

@TestPropertySource

注解中的

locations

properties

将覆盖先前的

@TestPropertySource

locations

properties

此外,你可以在一个测试类上声明多个组合注解,每个注解都用

@TestPropertySource

进行元注解,所有这些

@TestPropertySource

声明都将贡献给你的测试属性源。直接呈现的

@TestPropertySource注解

总是优先于元呈现的

@TestPropertySource

注解。换句话说,直接存在的

@TestPropertySource

locations

properties

将覆盖

@TestPropertySource

注解中用作元注解的

locations

properties

默认属性文件检测

@TestPropertySource

被声明为空注解(即,没有

locations

properties

的显式值),则尝试检测相对于声明该注解的类的默认属性文件。例如,如果带注解的测试类是

com.example.MyTest

,则相应的对应属性文件是

classpath:com/example/MyTest.properties

。如果无法检测到默认值,则抛出

IllegalStateException

优先顺序

测试属性的优先级高于在操作系统环境、Java系统属性或应用程序通过使用

@PropertySource

声明性地或以编程方式添加的属性源中定义的属性。因此,测试属性可用于有选择地覆盖从系统和应用程序属性源加载的属性。此外,内联属性优先于从资源位置加载的属性。但是请注意,通过

@DynamicPropertySource

注册的属性比通过

@TestPropertySource

加载的属性具有更高的优先级。

在下一个示例中,

timezone

port

属性以及在

/test.properties

中定义的任何属性都将覆盖在系统和应用程序属性源中定义的同名属性。此外,如果

/test.properties

文件定义了

timezone

port

属性的条目,则这些条目将被使用

properties

属性声明的内联属性所覆盖。

@ContextConfiguration
@TestPropertySource(
    locations = "/test.properties",
    properties = {"timezone = GMT", "port: 4242"}
)
class MyIntegrationTests {
    // class body...
}           

继承和覆盖测试属性源

@TestPropertySource

支持布尔型的

inheritLocations

inheritProperties

属性,它们表示属性文件的资源位置和超类声明的内联属性是否应该被继承。这两个标志的默认值为

true

。这意味着测试类将继承任何超类声明的位置和内联属性。具体来说,测试类的位置和内联属性附加到父类声明的位置和内联属性。因此,子类可以选择扩展位置和内联属性。注意,后面出现的属性会隐藏(即覆盖)前面出现的同名属性。此外,前面提到的优先规则也适用于继承的测试属性源。

@TestPropertySource

InheritLocations

InheritProperties

属性设置为

false

,则分别为测试类设置位置或内联属性,并有效替换超类定义的配置。

BaseTest

ApplicationContext

是通过只使用

base

加载的。属性文件作为测试属性源。相反,

ExtendedTest

ApplicationContext

是通过使用

base

加载的属性和扩展。属性文件作为测试属性源位置。下面的示例演示如何使用属性文件在子类及其超类中定义属性:

@TestPropertySource("base.properties")
@ContextConfiguration
class BaseTest {
   // ...
}

@TestPropertySource("extended.properties")
@ContextConfiguration
class ExtendedTest extends BaseTest {
   // ...
}           

在下一个示例中,仅使用内联的

key1

属性来加载

BaseTest

ApplicationContext

。相反,使用内联的

key1

key2

ExtendedTest

ApplicationContext

。下面的示例演示如何通过使用内联属性在子类及其父类中定义属性:

@TestPropertySource(properties = "key1 = value1")
@ContextConfiguration
class BaseTest {
    // ...
}

@TestPropertySource(properties = "key2 = value2")
@ContextConfiguration
class ExtendedTest extends BaseTest {
    // ...
}           

从Spring框架5.2.5开始,

TestContext

框架通过

@DynamicPropertySource

注解提供对动态属性的支持。此注解可用于需要向为集成测试加载的

ApplicationContext

的环境中的

PropertySources

集添加带有动态值的属性的集成测试。

@DynamicPropertySource

注解及其支持的基础结构最初旨在使基于

Testcontainers

的测试中的属性易于暴露于Spring集成测试。但是,此功能还可以用于其生命周期在测试的

ApplicationContext

之外维护的任何形式的外部资源。

与在类级别应用

@TestPropertySource

注解相反,

@DynamicPropertySource

必须应用于接受单个

DynamicPropertyRegistry

参数的静态方法,该参数用于向环境添加

名称/值

对。值是动态的,并通过

Supplier

提供,只有在解析属性时才调用

Supplier

。通常,方法引用被用来提供值,如下面的例子所示,它使用

Testcontainers

项目在Spring

ApplicationContext

之外管理一个Redis容器。通过

redis.host

redis.port

属性,测试的

ApplicationContext

中的组件可以使用托管Redis容器的IP地址和端口。这些属性可以通过Spring的环境抽象访问,或者直接注入到Spring管理的组件中,例如分别通过

@Value("${redis.host}")

@Value("${redis.port}")

@SpringJUnitConfig(/* ... */)
@Testcontainers
class ExampleIntegrationTests {

    @Container
    static RedisContainer redis = new RedisContainer();

    @DynamicPropertySource
    static void redisProperties(DynamicPropertyRegistry registry) {
        registry.add("redis.host", redis::getContainerIpAddress);
        registry.add("redis.port", redis::getMappedPort);
    }

    // tests ...

}           

动态属性的优先级高于

@TestPropertySource

、操作系统的环境、Java系统属性或应用程序通过

@PropertySource

声明性地或以编程方式添加的属性源中加载的属性。因此,动态属性可用于有选择地覆盖通过

@TestPropertySource

、系统属性源和应用程序属性源加载的属性。

WebApplicationContext

若要指示

TestContext

框架加载

WebApplicationContext

而不是标准

ApplicationContext

@WebAppConfiguration

注解各自的测试类。

测试类上

@WebAppConfiguration

的存在指示

TestContext

框架(TCF)应该为集成测试加载

WebApplicationContext

(WAC)。TCF在后台确保创建了

MockServletContext

并将其提供给测试的WAC。默认情况下,你的

MockServletContext

的基本资源路径设置为

src/main/webapp

。这被解释为相对于JVM根目录的路径(通常是项目的路径)。如果你熟悉Maven项目中Web应用程序的目录结构,则知道

src/main/webapp

是WAR根目录的默认位置。如果需要覆盖此默认值,则可以提供

@WebAppConfiguration

注解的替换路径(例如,

@WebAppConfiguration(“src/test/webapp”))

。如果你希望从类路径而不是文件系统中引用基本资源路径,则可以使用Spring的

classpath:

前缀。

请注意,Spring对

WebApplicationContext

实现的测试支持与其对标准

ApplicationContext

实现的支持相当。使用

WebApplicationContext

进行测试时,可以使用

@ContextConfiguration

声明XML配置文件、Groovy脚本或

@Configuration

类。你还可以自由地使用任何其他测试注解,如

@ActiveProfiles

@Testexecutionlistener

@Sql

@Rollback

和其他。

本节的其余示例展示了加载

WebApplicationContext

的一些不同配置选项。以下示例显示了

TestContext

框架对配置约定的支持:

@ExtendWith(SpringExtension.class)

// defaults to "file:src/main/webapp"
@WebAppConfiguration

// detects "WacTests-context.xml" in the same package
// or static nested @Configuration classes
@ContextConfiguration
class WacTests {
    //...
}           

如果使用

@WebAppConfiguration

注解测试类而未指定资源基本路径,则资源路径实际上默认为

file:src/main/webapp

。同样,如果在声明

@ContextConfiguration

时未指定资源位置、组件类或上下文初始化程序,则Spring会尝试使用约定(也就是说,

WacTests-context.xml

WacTests

类或静态嵌套

@Configuration

类位于同一包中)。

以下示例显示如何使用

@WebAppConfiguration

显式声明资源基本路径和使用

@ContextConfiguration

显式声明XML资源位置:

@ExtendWith(SpringExtension.class)

// file system resource
@WebAppConfiguration("webapp")

// classpath resource
@ContextConfiguration("/spring/test-servlet-config.xml")
class WacTests {
    //...
}           

这里要注意的重要一点是具有这两个注解的路径的语义不同。默认情况下,

@ WebAppConfiguration

资源路径基于文件系统,而

@ContextConfiguration

资源位置基于类路径。下面的示例显示,我们可以通过指定Spring资源前缀来覆盖两个注解的默认资源语义:

@ExtendWith(SpringExtension.class)

// classpath resource
@WebAppConfiguration("classpath:test-web-resources")

// file system resource
@ContextConfiguration("file:src/main/webapp/WEB-INF/servlet-config.xml")
class WacTests {
    //...
}           

将本示例中的注解与上一个示例进行对比。

使用Web Mock工作

为了提供全面的Web测试支持,

TestContext

框架具有默认启用的

ServletTestExecutionListener

。在针对

WebApplicationContext

进行测试时,此

TestExecutionListener

会在每个测试方法之前使用Spring Web的

RequestContextHolder

来设置默认的线程本地状态,并根据通过

@WebAppConfiguration

配置的基本资源路径创建

MockHttpServletRequest

MockHttpServletResponse

ServletWebRequest

ServletTestExecutionListener

还确保可以将

MockHttpServletResponse

ServletWebRequest

注入到测试实例中,并且一旦测试完成,它将清除线程本地状态。

一旦为测试加载了

WebApplicationContext

,你可能会发现你需要与Web模拟进行交互,例如,在调用Web组件之后设置测试

fixture

或执行断言。以下示例显示可以将哪些模拟自动装配到你的测试实例。请注意,

WebApplicationContext

MockServletContext

都缓存在测试套件中,而其他模拟则由

ServletTestExecutionListener

针对每个测试方法进行管理。

@SpringJUnitWebConfig
class WacTests {

    @Autowired
    WebApplicationContext wac; // cached

    @Autowired
    MockServletContext servletContext; // cached

    @Autowired
    MockHttpSession session;

    @Autowired
    MockHttpServletRequest request;

    @Autowired
    MockHttpServletResponse response;

    @Autowired
    ServletWebRequest webRequest;

    //...
}           

一旦

TestContext

框架为测试加载了

ApplicationContext

(或

WebApplicationContext

),该上下文将被缓存并重新用于在同一测试套件中声明相同唯一上下文配置的所有后续测试。要了解缓存的工作原理,重要的是要了解

unique

测试套件

的含义。

可以通过用于加载它的配置参数的组合来唯一标识

ApplicationContext

。因此,使用配置参数的唯一组合来生成一个键,在该键下缓存上下文。

TestContext

框架使用以下配置参数来构建上下文缓存键:

  • locations

    (来自

    @ContextConfiguration

    )
  • classes

    @ContextConfiguration

  • contextInitializerClasses

    @ContextConfiguration

  • contextCustomizers

    ContextCustomizerFactory

    )其中包括

    @DynamicPropertySource

    方法,以及Spring Boot测试支持中的各种功能,例如

    @MockBean

    @SpyBean

  • contextLoader

    @ContextConfiguration

  • parent

    @ContextHierarchy

  • activeProfiles

    @ActiveProfiles

  • propertySourceLocations

    @TestPropertySource

  • propertySourceProperties

    @TestPropertySource

  • resourceBasePath

    @WebAppConfiguration

例如,如果

TestClassA

@ContextConfiguration

location

value

)属性指定

{“app-config.xml”,“test-config.xml”}

,则

TestContext

框架将加载相应的

ApplicationContext

并将其存储在静态上下文缓存中仅基于那些位置的key下。因此,如果

TestClassB

还为其位置(通过继承显式或隐式)定义了

{“app-config.xml”,“test-config.xml”}

,但未定义

@WebAppConfiguration

、不同的

ContextLoader

、不同的激活配置文件、不同的上下文初始化程序、不同的测试属性源或不同的父上下文,则两个测试类将共享相同的

ApplicationContext

。这意味着(每个测试套件)仅需加载一次加载应用程序上下文的设置成本,并且随后的测试执行要快得多。

测试套件和分支流程

Spring

TestContext

框架将应用程序上下文存储在静态缓存中。这意味着上下文实际上是存储在静态变量中的。换句话说,如果测试是在单独的进程中执行的,则在每个测试执行之间都会清除静态缓存,从而有效地禁用了缓存机制。

为了从缓存机制中受益,所有测试必须在同一进程或测试套件中运行。这可以通过在IDE中以组的形式执行所有测试来实现。同样,在使用诸如Ant、Maven或Gradle之类的构建框架执行测试时,确保该构建框架不会在测试之间进行派生(fork多个进程)很重要。例如,如果将Maven Surefire插件的forkMode设置为always或pertest,则

TestContext

框架将无法在测试类之间缓存应用程序上下文,因此,构建过程的运行速度将大大降低。

上下文缓存的大小以默认的最大32为界。只要达到最大大小,就会使用最近最少使用(LRU)驱逐策略来驱逐和关闭旧的上下文。你可以通过设置名为

spring.test.context.cache.maxSize

的JVM系统属性,从命令行或构建脚本中配置最大大小。或者,你可以使用

SpringProperties

API以编程方式设置相同的属性。

由于在给定的测试套件中加载大量的应用程序上下文会导致该套件花费不必要的长时间来执行,因此准确地知道已加载和缓存了多少个上下文通常是有益的。要查看基础上下文缓存的统计信息,可以将

org.springframework.test.context.cache

日志记录类别的日志级别设置为

DEBUG

在不太可能的情况下,测试破坏了应用程序上下文并需要重新加载(例如,通过修改bean定义或应用程序对象的状态),你可以使用

@DirtiesContext

注解测试类或测试方法(请参阅

@DirtiesContext

中对

@DirtiesContext

的讨论)。这指示Spring在运行需要相同应用程序上下文的下一个测试之前,从缓存中删除上下文并重建应用程序上下文。请注意,默认情况下启用的

DirtiesContextBeforeModesTestExecutionListener

DirtiesContextTestExecutionListener

提供了对

@DirtiesContext

注解的支持。

在编写依赖于已加载的Spring

ApplicationContext

的集成测试时,通常足以针对单个上下文进行测试。但是,有时需要对

ApplicationContext

实例的层次结构进行测试是有益的,甚至是必要的。例如,如果你正在开发Spring MVC Web应用程序,则通常由Spring的

ContextLoaderListener

加载根

WebApplicationContext

,由Spring的

DispatcherServlet

加载子

WebApplicationContext

。这将导致父子上下文层次结构,其中共享组件和基础设施配置在根上下文中声明,并由特定于web的组件在子上下文中使用。在Spring Batch应用程序中可以找到另一个用例,在该应用程序中,你通常具有一个父上下文,该上下文为共享批处理基础结构提供配置,而子上下文则为特定批处理作业的配置提供配置。

你可以通过在单个测试类上或在测试类层次结构中使用

@ContextHierarchy

注解声明上下文配置来编写使用上下文层次结构的集成测试。如果在测试类层次结构中的多个类上声明了上下文层次结构,则还可以合并或覆盖上下文层次结构中特定命名级别的上下文配置。合并层次结构中给定级别的配置时,配置资源类型(即XML配置文件或组件类)必须一致。否则,在使用不同资源类型配置的上下文层次结构中具有不同级别是完全可以接受的。

本节中其余的基于JUnit Jupiter的示例显示了需要使用上下文层次结构的集成测试的常见配置方案。

具有上下文层次结构的单个测试类

ControllerIntegrationTests

通过声明一个上下文层次结构来代表Spring MVC Web应用程序的典型集成测试场景,该上下文层次结构包含两个级别,一个层次用于根

WebApplicationContext

(通过使用

TestAppConfig

@Configuration类加载),一个层次用于调度程序Servlet

WebApplicationContext

WebConfig

@Configuration

类加载)。自动装配到测试实例的

WebApplicationContext

是用于子上下文(即,层次结构中的最低上下文)的

WebApplicationContext

以下清单显示了此配置方案:

@ExtendWith(SpringExtension.class)
@WebAppConfiguration
@ContextHierarchy({
    @ContextConfiguration(classes = TestAppConfig.class),
    @ContextConfiguration(classes = WebConfig.class)
})
class ControllerIntegrationTests {

    @Autowired
    WebApplicationContext wac;

    // ...
}           

org.liyong.test.annotation.test.spring.ControllerIntegrationTests

具有隐式父上下文的类层次结构

本示例中的测试类在测试类层次结构中定义了上下文层次结构。

AbstractWebTests

在Spring驱动的Web应用程序中声明根

WebApplicationContext

的配置。但是请注意,

AbstractWebTests

不会声明

@ContextHierarchy

AbstractWebTests

的子类可以选择参与上下文层次结构或遵循

@ContextConfiguration

的标准语义。

SoapWebServiceTests

RestWebServiceTests

都扩展了

AbstractWebTests

@ContextHierarchy

定义了上下文层次结构。结果是,加载了三个应用程序上下文(每个

@ContextConfiguration

声明一个),并且基于

AbstractWebTests

中的配置加载的应用程序上下文被设置为具体子类加载的每个上下文的父上下文。

@ExtendWith(SpringExtension.class)
@WebAppConfiguration
@ContextConfiguration("file:src/main/webapp/WEB-INF/applicationContext.xml")
public abstract class AbstractWebTests {}

@ContextHierarchy(@ContextConfiguration("/spring/soap-ws-config.xml"))
public class SoapWebServiceTests extends AbstractWebTests {}

@ContextHierarchy(@ContextConfiguration("/spring/rest-ws-config.xml"))
public class RestWebServiceTests extends AbstractWebTests {}           

org.liyong.test.annotation.test.spring.RestWebServiceTests

合并上下文层次结构配置的类层次结构

此示例中的类显示了使用命名层次结构级别的目的,以及合并上下文层次结构中特定级别的配置。

BaseTests

在层次结构中定义了两个级别,

parent

child

ExtendedTests

扩展

BaseTests

并指示Spring

TestContext

框架合并子层次结构级别的上下文配置,方法是确保在

@ContextConfiguration

的name属性中声明的名称均为子元素。结果是加载了三个应用程序上下文:一个用于

/app-config.xml

、一个用于

/user-config.xml

{/user-config.xml

/order-config.xml}

。与前面的示例一样,将从

/app-config.xml

加载的应用程序上下文设置为从

/user-config.xml

{“/user-config.xml","/order-config.xml“}

加载的上下文的父上下文(合并配置文件)。以下清单显示了此配置方案:

@ExtendWith(SpringExtension.class)
@ContextHierarchy({
    @ContextConfiguration(name = "parent", locations = "/app-config.xml"),
    @ContextConfiguration(name = "child", locations = "/user-config.xml")
})
class BaseTests {}

@ContextHierarchy(
    @ContextConfiguration(name = "child", locations = "/order-config.xml")
)
class ExtendedTests extends BaseTests {}           

org.liyong.test.annotation.test.spring.ExtendedTests

具有覆盖的上下文层次结构配置的类层次结构

与前面的示例相反,此示例演示了如何通过将

@ContextConfiguration

InheritLocations

标志设置为

false

来覆盖上下文层次结构中给定命名级别的配置。因此,

ExtendedTests

的应用程序上下文仅从

/test-user-config.xml

加载,并且其父级设置为从

/app-config.xml

加载的上下文。以下清单显示了此配置方案:

@ExtendWith(SpringExtension.class)
@ContextHierarchy({
    @ContextConfiguration(name = "parent", locations = "/app-config.xml"),
    @ContextConfiguration(name = "child", locations = "/user-config.xml")
})
class BaseTests {}

@ContextHierarchy(
    @ContextConfiguration(
        name = "child",
        locations = "/test-user-config.xml",
        inheritLocations = false
))
class ExtendedTests extends BaseTests {}           

清除上下文层次结构中的上下文

如果你在一个测试中使用@DirtiesContext,该测试的上下文被配置为上下文层次结构的一部分,那么你可以使用hierarchyMode标志来控制如何清除上下文缓存。有关更多详细信息,请参见

Spring Testing Annotations 中的@DirtiesContext和 javadoc的讨论。

org.liyong.test.annotation.test.spring.ExtendedTests1

3.5.6 测试装置的依赖注入

当使用

DependencyInjectionTestExecutionListener

(默认配置)时,测试实例的依赖项是从使用

@ContextConfiguration

或相关注解配置应用程序上下文中的bean注入的。你可以使用

setter

注入、字段注入、或同时使用这两种方法,具体取决于你选择的注解以及是否将它们放在

setter

方法或字段上。如果你使用的是JUnit Jupiter,则还可以选择使用构造函数注入(请参阅带有

SpringExtension的依赖注入

)。为了与Spring基于注解的注入支持保持一致,你还可以将Spring的

@Autowired

注解或JSR-330中的

@Inject

注解用于字段注入和setter 注入。

对于JUnit Jupiter以外的测试框架,

TestContext

框架不参与测试类的实例化。因此,将

@Autowired

@Inject

用于构造函数对测试类无效。

尽管在生产代码中不鼓励使用字段注入,但是在测试代码中字段注入实际上是很自然的。理由是你永远不会直接实例化测试类。因此,不需要在测试类上调用公共构造函数或

setter

方法。

因为

@Autowired

用于按类型执行自动装配,所以如果你具有多个相同类型的Bean定义,那么对于那些特定的Bean,你将不能依靠这种方法。在这种情况下,可以将

@Autowired

@Qualifier

结合使用。你也可以选择将

@Inject

@Named

结合使用。或者,如果你的测试类可以访问其

ApplicationContext

,则可以通过使用(例如)对

applicationContext.getBean(“ titleRepository“,TitleRepository.class)

的调用来执行显式查找。

如果你不希望将依赖项注入应用于测试实例,请不要使用

@Autowired

@Inject

注解字段或设置器方法。或者,你可以通过显式地用

@TestExecutionListeners

配置你的类,并从监听器列表中忽略

DependencyInjectionTestExecutionListener.class

来禁用依赖注入。

考虑测试

HibernateTitleRepository

类的场景,如

目标

部分所述。接下来的两个代码清单演示了

@Autowired

在字段和

setter

方法上的用法。在所有示例代码清单之后显示了应用程序上下文配置。

以下代码清单中的依赖项注入行为并非特定于JUnit Jupiter。相同的

DI

技术可以与任何受支持的测试框架结合使用。

以下示例对静态断言方法(例如

assertNotNull()

)进行了调用,但没有在声明前添加

Assertions

。在这种情况下,假定该方法是通过示例中未显示的

import static

声明正确导入的。

第一个代码清单显示了使用

@Autowired

进行字段注入的测试类的基于JUnit Jupiter的实现:

@ExtendWith(SpringExtension.class)
// specifies the Spring configuration to load for this test fixture
@ContextConfiguration("repository-config.xml")
class HibernateTitleRepositoryTests {

    // this instance will be dependency injected by type
    @Autowired
    HibernateTitleRepository titleRepository;

    @Test
    void findById() {
        Title title = titleRepository.findById(new Long(10));
        assertNotNull(title);
    }
}           

或者,你可以将类配置为使用

@Autowired

进行

setter

注入,如下所示:

@ExtendWith(SpringExtension.class)
// specifies the Spring configuration to load for this test fixture
@ContextConfiguration("repository-config.xml")
class HibernateTitleRepositoryTests {

    // this instance will be dependency injected by type
    HibernateTitleRepository titleRepository;

    @Autowired
    void setTitleRepository(HibernateTitleRepository titleRepository) {
        this.titleRepository = titleRepository;
    }

    @Test
    void findById() {
        Title title = titleRepository.findById(new Long(10));
        assertNotNull(title);
    }
}           

前面的代码清单使用

@ContextConfiguration

注解引用的相同XML上下文文件(即,

repository-config.xml

)。下面显示了此配置:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <!-- this bean will be injected into the HibernateTitleRepositoryTests class -->
    <bean id="titleRepository" class="com.foo.repository.hibernate.HibernateTitleRepository">
        <property name="sessionFactory" ref="sessionFactory"/>
    </bean>

    <bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
        <!-- configuration elided for brevity -->
    </bean>

</beans>           
如果你是从Spring提供的测试基类扩展而来的,而该基类恰巧在其

setter

方法之一上使用

@Autowired

,则可能在应用程序上下文中定义了多个受影响类型的Bean(例如,多个

DataSource

Bean)。在这种情况下,你可以覆盖setter方法,并使用

@Qualifier

注解指示特定的目标bean,如下所示(但请确保也委托给超类中的重写方法):
// ...

 @Autowired
 @Override
 public void setDataSource(@Qualifier("myDataSource") DataSource dataSource) {
     super.setDataSource(dataSource);
 }

// ...           
指定的限定符值指示要注入的特定

DataSource

Bean,从而将类型匹配的范围缩小到特定Bean。其值与相应的定义中的声明匹配。Bean名称用作后备限定符值,因此你也可以在该名称中有效地指向特定的Bean(如先前所示,假设

myDataSource

是Bean

ID

作者

个人从事金融行业,就职过易极付、思建科技、某网约车平台等重庆一流技术团队,目前就职于某银行负责统一支付系统建设。自身对金融行业有强烈的爱好。同时也实践大数据、数据存储、自动化集成和部署、分布式微服务、响应式编程、人工智能等领域。同时也热衷于技术分享创立公众号和博客站点对知识体系进行分享。关注公众号:青年IT男 获取最新技术文章推送!

博客地址:

http://youngitman.tech

CSDN:

https://blog.csdn.net/liyong1028826685

微信公众号:

Spring 5 中文解析核心篇-集成测试之TestContext(中)

技术交流群:

Spring 5 中文解析核心篇-集成测试之TestContext(中)