乐趣区

关于spring:Spring-5-中文解析核心篇集成测试之TestContext中

3.5.5 上下文治理

每个 TestContext 为其负责的测试实例提供上下文治理和缓存反对。测试实例不会主动接管对配置的 ApplicationContext 的拜访。然而,如果测试类实现 ApplicationContextAware 接口,则将对 ApplicationContext 的援用提供给测试实例。请留神,AbstractJUnit4SpringContextTestsAbstractTestNGSpringContextTests 实现了 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 资源配置上下文
  • 通过 Groovy 脚本配置上下文
  • 通过组件类配置上下文
  • XML、Groovy 脚本、组件类混合
  • 通过上下文初始化器配置上下文
  • 上下文配置继承
  • 通过环境配置配置上下文
  • 通过测试属性源配置上下文
  • 通过动静属性源配置上下文
  • 加载 WebApplicationContext
  • 上下文缓存
  • 上下文层级

通过 XML 资源配置上下文

若要应用 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 资源地位。具体而言,GenericXmlContextLoaderGenericXmlWebContextLoader 依据测试类的名称检测默认地位。如果你的类名为 com.example.MyTestGenericXmlContextLoaderclasspath: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 脚本配置上下文

要通过应用 Groovy Bean 定义 DSL 的 Groovy 脚本为测试加载 ApplicationContext,能够应用@ContextConfiguration 注解测试类,并应用蕴含 Groovy 脚本资源地位的数组配置 locationvalue属性。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 注解中省略了 locationvalue属性,则 TestContext 框架将尝试检测默认的 Groovy 脚本。具体来说,GenericGroovyXmlContextLoaderGenericGroovyXmlWebContextLoader 依据测试类的名称检测默认地位。如果你的类名为 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...}
  1. 从默认地位加载配置。

同时申明 XML 配置和 Groovy 脚本

你能够应用 @ContextConfigurationlocationvalue 属性同时申明 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 框架将尝试检测默认配置类的存在。具体来说,AnnotationConfigContextLoaderAnnotationConfigWebContextLoader 检测到满足配置类实现要求的测试类的所有动态嵌套类,如 @Configuration 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 脚本、组件类混合

有时可能须要混合应用 XML 配置文件、Groovy 脚本和组件类 (通常为@Configuration 类)来为测试配置 ApplicationContext。如果在生产中应用 XML 配置,则能够决定要应用@Configuration 类为测试配置特定的 Spring 托管组件,反之亦然。

此外,某些第三方框架(例如 Spring Boot)提供了一流的反对,能够同时从不同类型的资源(例如 XML 配置文件、Groovy 脚本和 @Configuration 类)中加载 ApplicationContext。过来,Spring 框架不反对此规范部署。因而,Spring 框架在spring-test 模块中提供的大多数 SmartContextLoader 实现对于每个测试上下文仅反对一种资源类型。然而,这并不意味着你不能同时应用两者。通用规定的一个例外是 GenericGroovyXmlContextLoaderGenericGroovyXmlWebContextLoader同时反对 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 inheritLocationsinheritinitialalizer属性,它们示意是否应该继承由超类申明的资源地位或组件类和上下文初始化器。这两个标记的默认值为true。这意味着测试类将继承资源地位或组件类以及任何超类申明的上下文初始化器。具体来说,将测试类的资源地位或组件类附加到由超类申明的资源地位或带注解的类的列表中。同样,将给定测试类的初始化程序增加到由测试超类定义的初始化程序集。因而,子类能够抉择扩大资源地位、组件类或上下文初始化程序。

如果 @ContextConfiguration 中的 inheritLocationsinheritInitializers属性被设置为false,则测试类的资源地位或组件类和上下文初始化器将别离无效地代替超类定义的配置。

在下一个应用 XML 资源地位的示例中,从 Base-config.xmlExtended-config.xml 依 次加载 ExtendedContextApplicationContext。因而,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. 子类中定义的配置文件。

同样,在下一个应用组件类的示例中,从 BaseConfigExtendedConfig类按该程序加载 ExtendedTestApplicationContext。因而,在 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. 在子类中定义的配置类。

在应用上下文初始化程序的下一个示例中,通过应用 BaseInitializerExtendedInitializer初始化 ExtendedTestApplicationContext。然而请留神,初始化程序的调用程序取决于它们是实现 Spring 的 Ordered 接口还是以 Spring 的 @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 时应激活的配置文件列表来实现。

你能够将 @ActiveProfilesSmartContextLoader 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。例如,你能够显式提供 devproduction的数据源,然而当两者都不处于活动状态时,将内存中数据源定义为默认值。

以下代码清单演示了如何应用 @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 并应用 @ActiveProfilesresolver属性对其进行注册。无关更多信息,请参见相应的 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 注解,以申明测试属性文件或内联属性的资源地位。这些测试属性源被增加到环境中为带注解的集成测试加载的 ApplicationContextPropertySources汇合中。

你能够将 @TestPropertySourceSmartContextLoader SPI 的任何实现一起应用,然而较早的ContextLoader SPI 的实现不反对@TestPropertySource

SmartContextLoader的实现可通过 MergedContextConfiguration 中的 getPropertySourceLocations()getPropertySourceProperties()办法拜访合并的测试属性源值。

申明测试属性源

你能够应用 @TestPropertySource 的 locationvalue属性来配置测试属性文件。

反对传统属性文件格式和基于 XML 的属性文件格式,例如:classpath:/com/example/test.propertiesfile:///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. 指定具备绝对路径的属性文件。

你能够应用 @TestPropertySourceproperties属性,以键 / 值对的模式配置内联属性,如下例所示。所有键值对都作为优先级最高的单个测试 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 注解中的 locationsproperties将笼罩先前的 @TestPropertySource 注解中的 locationsproperties

此外,你能够在一个测试类上申明多个组合注解,每个注解都用 @TestPropertySource 进行元注解,所有这些 @TestPropertySource 申明都将奉献给你的测试属性源。间接出现的 @TestPropertySource 注解 总是优先于元出现的 @TestPropertySource 注解。换句话说,间接存在的 @TestPropertySource 注解中的 locationsproperties将笼罩 @TestPropertySource 注解中用作元注解的 locationsproperties

默认属性文件检测

如果 @TestPropertySource 被申明为空注解(即,没有 locationsproperties的显式值),则尝试检测绝对于申明该注解的类的默认属性文件。例如,如果带注解的测试类是com.example.MyTest,则相应的对应属性文件是classpath:com/example/MyTest.properties。如果无奈检测到默认值,则抛出IllegalStateException

优先程序

测试属性的优先级高于在操作系统环境、Java 零碎属性或应用程序通过应用 @PropertySource 申明性地或以编程形式增加的属性源中定义的属性。因而,测试属性可用于有选择地笼罩从零碎和应用程序属性源加载的属性。此外,内联属性优先于从资源地位加载的属性。然而请留神,通过 @DynamicPropertySource 注册的属性比通过 @TestPropertySource 加载的属性具备更高的优先级。

在下一个示例中,timezoneport 属性以及在 /test.properties 中定义的任何属性都将笼罩在零碎和应用程序属性源中定义的同名属性。此外,如果 /test.properties 文件定义了 timezoneport属性的条目,则这些条目将被应用 properties 属性申明的内联属性所笼罩。

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

继承和笼罩测试属性源

@TestPropertySource反对布尔型的 inheritLocationsinheritProperties属性,它们示意属性文件的资源地位和超类申明的内联属性是否应该被继承。这两个标记的默认值为 true。这意味着测试类将继承任何超类申明的地位和内联属性。具体来说,测试类的地位和内联属性附加到父类申明的地位和内联属性。因而,子类能够抉择扩大地位和内联属性。留神,前面呈现的属性会暗藏(即笼罩) 后面呈现的同名属性。此外,后面提到的优先规定也实用于继承的测试属性源。

如果 @TestPropertySource 中的 InheritLocationsInheritProperties属性设置为false,则别离为测试类设置地位或内联属性,并无效替换超类定义的配置。

在下一个示例中,BaseTestApplicationContext 是通过只应用 base 加载的。属性文件作为测试属性源。相同,ExtendedTestApplicationContext 是通过应用 base 加载的属性和扩大。属性文件作为测试属性源地位。上面的示例演示如何应用属性文件在子类及其超类中定义属性:

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

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

在下一个示例中,仅应用内联的 key1 属性来加载 BaseTestApplicationContext。相同,应用内联的 key1key2属性来加载 ExtendedTestApplicationContext。上面的示例演示如何通过应用内联属性在子类及其父类中定义属性:

@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.hostredis.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.xmlWacTests 类或动态嵌套 @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 配置的根本资源门路创立 MockHttpServletRequestMockHttpServletResponseServletWebRequest

ServletTestExecutionListener还确保能够将 MockHttpServletResponseServletWebRequest注入到测试实例中,并且一旦测试实现,它将革除线程本地状态。

一旦为测试加载了 WebApplicationContext,你可能会发现你须要与 Web 模仿进行交互,例如,在调用 Web 组件之后设置测试fixture 或执行断言。以下示例显示能够将哪些模仿主动拆卸到你的测试实例。请留神,WebApplicationContextMockServletContext 都缓存在测试套件中,而其余模仿则由 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@ContextConfigurationlocation(或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 在运行须要雷同应用程序上下文的下一个测试之前,从缓存中删除上下文并重建应用程序上下文。请留神,默认状况下启用的 DirtiesContextBeforeModesTestExecutionListenerDirtiesContextTestExecutionListener提供了对 @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 的规范语义。SoapWebServiceTestsRestWebServiceTests 都扩大了 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在层次结构中定义了两个级别,parentchildExtendedTests 扩大 BaseTests 并批示 Spring TestContext 框架合并子层次结构级别的上下文配置,办法是 <u> 确保在 @ContextConfiguration 的 name 属性中申明的名称均为子元素 </u>。后果是加载了三个应用程序上下文:一个用于 /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 和 @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> 定义中的 <qualifier> 申明匹配。Bean 名称用作后备限定符值,因而你也能够在该名称中无效地指向特定的 Bean(如先前所示,假如myDataSource 是 Bean ID)。

作者

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

博客地址: http://youngitman.tech

CSDN: https://blog.csdn.net/liyong1…

微信公众号:

技术交换群:

退出移动版