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

3.5.5 上下文管理

每一個TestContext爲其負責的測試實例提供上下文管理和緩存支持。測試實例不會自動接收對配置的ApplicationContext的訪問。可是,若是測試類實現ApplicationContextAware接口,則將對ApplicationContext的引用提供給測試實例。請注意,AbstractJUnit4SpringContextTestsAbstractTestNGSpringContextTests實現了ApplicationContextAware,所以能夠自動提供對ApplicationContext的訪問。html

@Autowired ApplicationContextjava

做爲實現ApplicationContextAware接口的替代方法,你能夠經過字段或setter方法上的@Autowired註解爲測試類注入應用程序上下文,如如下示例所示:git

@SpringJUnitConfig
class MyTest {

 @Autowired //1
 ApplicationContext applicationContext;

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

一樣,若是將測試配置爲加載WebApplicationContext,則能夠將Web應用程序上下文注入到測試中,以下所示:web

@SpringJUnitWebConfig //1
class MyWebAppTest {

    @Autowired //2
    WebApplicationContext wac;

    // class body...
}
  1. 配置WebApplicationContext
  2. 注入WebApplicationContext

使用@Autowired的依賴關係注入是DependencyInjectionTestExecutionListener提供的,它是默認配置的(參見測試裝置的依賴注入)。redis

使用TestContext框架的測試類不須要擴展任何特定的類或實現特定的接口來配置其應用程序上下文。而是經過在類級別聲明@ContextConfiguration註解來實現配置。若是你的測試類未明確聲明應用程序上下文資源位置或組件類,則配置的ContextLoader將肯定如何從默認位置或默認配置類加載上下文。除了上下文資源位置和組件類以外,還能夠經過應用程序上下文初始化程序配置應用程序上下文。spring

如下各節說明如何使用Spring的@ContextConfiguration註解經過XML配置文件、Groovy腳本、組件類(一般爲@Configuration類)或上下文初始化器來配置測試ApplicationContext。另外,你能夠爲高級用例實現和配置本身的自定義SmartContextLoadersql

經過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屬性名稱的聲明並聲明資源位置。api

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

微信公衆號:

技術交流羣:

相關文章
相關標籤/搜索