溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

怎么用XML資源配置上下文

發(fā)布時(shí)間:2021-12-22 11:55:41 來源:億速云 閱讀:178 作者:iii 欄目:大數(shù)據(jù)

本篇內(nèi)容主要講解“怎么用XML資源配置上下文”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實(shí)用性強(qiáng)。下面就讓小編來帶大家學(xué)習(xí)“怎么用XML資源配置上下文”吧!

上下文管理

每個(gè)TestContext為其負(fù)責(zé)的測試實(shí)例提供上下文管理和緩存支持。測試實(shí)例不會自動接收對配置的ApplicationContext的訪問。但是,如果測試類實(shí)現(xiàn)ApplicationContextAware接口,則將對ApplicationContext的引用提供給測試實(shí)例。請注意,AbstractJUnit4SpringContextTestsAbstractTestNGSpringContextTests實(shí)現(xiàn)了ApplicationContextAware,因此可以自動提供對ApplicationContext的訪問。

@Autowired ApplicationContext

作為實(shí)現(xiàn)ApplicationContextAware接口的替代方法,你可以通過字段或setter方法上的@Autowired注解為測試類注入應(yīng)用程序上下文,如以下示例所示:

@SpringJUnitConfig
class MyTest {

 @Autowired //1
 ApplicationContext applicationContext;

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

同樣,如果將測試配置為加載WebApplicationContext,則可以將Web應(yīng)用程序上下文注入到測試中,如下所示:

@SpringJUnitWebConfig //1
class MyWebAppTest {

    @Autowired //2
    WebApplicationContext wac;

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

  2. 注入WebApplicationContext

使用@Autowired的依賴關(guān)系注入是DependencyInjectionTestExecutionListener提供的,它是默認(rèn)配置的(參見測試裝置的依賴注入)。

使用TestContext框架的測試類不需要擴(kuò)展任何特定的類或?qū)崿F(xiàn)特定的接口來配置其應(yīng)用程序上下文。而是通過在類級別聲明@ContextConfiguration注解來實(shí)現(xiàn)配置。如果你的測試類未明確聲明應(yīng)用程序上下文資源位置或組件類,則配置的ContextLoader將確定如何從默認(rèn)位置或默認(rèn)配置類加載上下文。除了上下文資源位置和組件類之外,還可以通過應(yīng)用程序上下文初始化程序配置應(yīng)用程序上下文。

以下各節(jié)說明如何使用Spring的@ContextConfiguration注解通過XML配置文件、Groovy腳本、組件類(通常為@Configuration類)或上下文初始化器來配置測試ApplicationContext。另外,你可以為高級用例實(shí)現(xiàn)和配置自己的自定義SmartContextLoader。

  • 通過XML資源配置上下文

  • 通過Groovy腳本配置上下文

  • 通過組件類配置上下文

  • XML、Groovy腳本、組件類混合

  • 通過上下文初始化器配置上下文

  • 上下文配置繼承

  • 通過環(huán)境配置配置上下文

  • 通過測試屬性源配置上下文

  • 通過動態(tài)屬性源配置上下文

  • 加載 WebApplicationContext

  • 上下文緩存

  • 上下文層級

通過XML資源配置上下文

若要使用XML配置文件為測試加載ApplicationContext,請使用@ContextConfiguration注解測試類,并使用包含XML配置元數(shù)據(jù)的資源位置的數(shù)組配置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屬性設(shè)置為XML文件列表。

@ContextConfiguration通過標(biāo)準(zhǔn)Java值屬性為locations屬性支持別名。因此,如果不需要在@ContextConfiguration中聲明其他屬性,你可以使用以下示例中演示的格式,省略locations屬性名稱的聲明并聲明資源位置。

@ExtendWith(SpringExtension.class)
@ContextConfiguration({"/app-config.xml", "/test-config.xml"}) //1
class MyTest {
    // class body...
}
  1. 不使用location屬性指定XML文件。

如果你從@ContextConfiguration注解中省略了位置和值屬性,則TestContext框架將嘗試檢測默認(rèn)的XML資源位置。具體而言,GenericXmlContextLoaderGenericXmlWebContextLoader根據(jù)測試類的名稱檢測默認(rèn)位置。如果你的類名為com.example.MyTestGenericXmlContextLoaderclasspath:com/example/MyTest-context.xml加載應(yīng)用程序上下文。以下示例顯示了如何執(zhí)行此操作:

@ExtendWith(SpringExtension.class)
// ApplicationContext will be loaded from
// "classpath:com/example/MyTest-context.xml"
@ContextConfiguration //1
class MyTest {
    // class body...
}
  1. 從默認(rèn)位置加載配置。

通過Groovy腳本配置上下文

要通過使用Groovy Bean定義DSL的Groovy腳本為測試加載ApplicationContext,可以使用@ContextConfiguration注解測試類,并使用包含Groovy腳本資源位置的數(shù)組配置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框架將嘗試檢測默認(rèn)的Groovy腳本。具體來說,GenericGroovyXmlContextLoaderGenericGroovyXmlWebContextLoader根據(jù)測試類的名稱檢測默認(rèn)位置。如果你的類名為com.example.MyTest則Groovy上下文加載器將從classpath:com/example/MyTestContext.groovy加載應(yīng)用程序上下文。下面的示例演示如何使用默認(rèn)值:

@ExtendWith(SpringExtension.class)
// ApplicationContext will be loaded from
// "classpath:com/example/MyTestContext.groovy"
@ContextConfiguration //1
class MyTest {
    // class body...
}
  1. 從默認(rèn)位置加載配置。

同時(shí)聲明XML配置和Groovy腳本

你可以使用@ContextConfigurationlocationvalue屬性同時(shí)聲明XML配置文件和Groovy腳本。如果到配置的資源位置的路徑以.xml結(jié)尾,則使用XmlBeanDefinitionReader加載該路徑。否則,將使用GroovyBeanDefinitionReader加載它。

以下清單顯示了如何在集成測試中將兩者結(jié)合起來:

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

通過組件類配置上下文

要使用組件類(請參見基于Java的容器配置)為測試加載ApplicationContext,可以使用@ContextConfiguration注解測試類,并使用包含對組件類的引用的數(shù)組來配置classes屬性。以下示例顯示了如何執(zhí)行此操作:

@ExtendWith(SpringExtension.class)
// ApplicationContext將從AppConfig和TestConfig加載上下文
@ContextConfiguration(classes = {AppConfig.class, TestConfig.class}) //1
class MyTest {
    // class body...
}
  1. 指定組件類。

組件類

術(shù)語組件類可以指以下任何一種:

  • @Configuration注解的類。

  • 組件(即,用@Component、@Service、@Repository或其他構(gòu)造型注解注釋的類)。

  • 與JSR-330兼容的類,該類使用javax.inject注解進(jìn)行了注釋。

  • 包含@Bean方法的任何類。

  • 打算注冊為Spring組件的任何其他類(即ApplicationContext中的Spring bean),可能利用單個(gè)自動構(gòu)造函數(shù)的自動裝配而無需使用Spring注解。

有關(guān)組件類的配置和語義的更多信息,請參見@Configuration和@Bean的javadoc,尤其要注意@Bean Lite模式的討論。

如果你從@ContextConfiguration注解中省略了classes屬性,則TestContext框架將嘗試檢測默認(rèn)配置類的存在。具體來說,AnnotationConfigContextLoaderAnnotationConfigWebContextLoader檢測到滿足配置類實(shí)現(xiàn)要求的測試類的所有靜態(tài)嵌套類,如@Configuration javadoc中所指定。請注意,配置類的名稱是任意的。另外,如果需要,一個(gè)測試類可以包含多個(gè)靜態(tài)嵌套配制類。在以下示例中,OrderServiceTest類聲明一個(gè)名為Config的靜態(tài)嵌套配置類,該配置類將自動用于為測試類加載ApplicationContext

@SpringJUnitConfig //1
// ApplicationContext將從內(nèi)部潛逃靜態(tài)累加載
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腳本、組件類混合

有時(shí)可能需要混合使用XML配置文件、Groovy腳本和組件類(通常為@Configuration類)來為測試配置ApplicationContext。如果在生產(chǎn)中使用XML配置,則可以決定要使用@Configuration類為測試配置特定的Spring托管組件,反之亦然。

此外,某些第三方框架(例如Spring Boot)提供了一流的支持,可以同時(shí)從不同類型的資源(例如XML配置文件、Groovy腳本和@Configuration類)中加載ApplicationContext。過去,Spring框架不支持此標(biāo)準(zhǔn)部署。因此,Spring框架在spring-test模塊中提供的大多數(shù)SmartContextLoader實(shí)現(xiàn)對于每個(gè)測試上下文僅支持一種資源類型。但是,這并不意味著你不能同時(shí)使用兩者。通用規(guī)則的一個(gè)例外是GenericGroovyXmlContextLoaderGenericGroovyXmlWebContextLoader同時(shí)支持XML配置文件和Groovy腳本。此外,第三方框架可以選擇通過@ContextConfiguration支持位置和類的聲明,并且,借助TestContext框架中的標(biāo)準(zhǔn)測試支持,你可以選擇以下選項(xiàng)。

如果要使用資源位置(例如XML或Groovy)和@Configuration類的配置測試,則必須選擇一個(gè)作為入口點(diǎn),并且其中一個(gè)必須包含或?qū)肓硪粋€(gè)。例如,在XML或Groovy腳本中,可以通過使用組件掃描或?qū)⑺鼈兌x為普通的Spring bean來包括@Configuration類,而在@Configuration類中,可以使用@ImportResource導(dǎo)入XML配置文件或Groovy腳本。請注意,此行為在語義上等同于你在生產(chǎn)環(huán)境中配置應(yīng)用程序的方式:在生產(chǎn)配置中,你定義了一組XML或Groovy資源位置或一組@Configuration類,從中加載了生產(chǎn)ApplicationContext,但是你仍然包含或?qū)肫渌愋偷呐渲玫淖杂伞?/p>

通過上下文初始化器配置上下文

若要使用上下文初始化程序?yàn)槟愕臏y試配置ApplicationContext,請使用@ContextConfiguration注解測試類,并使用包含對實(shí)現(xiàn)ApplicationContextInitializer的類的引用的數(shù)組配置初始化程序?qū)傩浴H缓?,使用聲明的上下文初始值設(shè)定項(xiàng)來初始化為測試加載的ConfigurableApplicationContext。請注意,每個(gè)聲明的初始化程序支持的具體ConfigurableApplicationContext類型必須與使用中的SmartContextLoader創(chuàng)建的ApplicationContext類型(通常是GenericApplicationContext)兼容。此外,初始化程序的調(diào)用順序取決于它們是實(shí)現(xiàn)Spring的Ordered接口還是以Spring的@Order注解或標(biāo)準(zhǔn)的@Priority注解進(jìn)行注釋。下面的示例演示如何使用初始化程序:

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

你還可以完全省略@ContextConfiguration中的XML配置文件、Groovy腳本或組件類的聲明,而僅聲明ApplicationContextInitializer類,然后這些類負(fù)責(zé)在上下文中注冊Bean(例如,通過編程方式從XML文件加載Bean定義)或配置類。以下示例顯示了如何執(zhí)行此操作:

@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屬性,它們表示是否應(yīng)該繼承由超類聲明的資源位置或組件類和上下文初始化器。這兩個(gè)標(biāo)志的默認(rèn)值為true。這意味著測試類將繼承資源位置或組件類以及任何超類申明的上下文初始化器。具體來說,將測試類的資源位置或組件類附加到由超類申明的資源位置或帶注解的類的列表中。同樣,將給定測試類的初始化程序添加到由測試超類定義的初始化程序集。因此,子類可以選擇擴(kuò)展資源位置、組件類或上下文初始化程序。

如果@ContextConfiguration中的inheritLocationsinheritInitializers屬性被設(shè)置為false,則測試類的資源位置或組件類和上下文初始化器將分別有效地替代超類定義的配置。

在下一個(gè)使用XML資源位置的示例中,從Base-config.xmlExtended-config.xml依次加載ExtendedContextApplicationContext。因此,extended-config.xml中定義的Bean可以覆蓋(即替換)base-config.xml中定義的那些。以下示例顯示了一個(gè)類如何擴(kuò)展另一個(gè)類并使用其自己的配置文件和超類的配置文件:

@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. 子類中定義的配置文件。

同樣,在下一個(gè)使用組件類的示例中,從BaseConfigExtendedConfig類按該順序加載ExtendedTestApplicationContext。因此,在ExtendedConfig中定義的Bean可以覆蓋(即替換)在BaseConfig中定義的Bean。下面的示例顯示一個(gè)類如何擴(kuò)展另一個(gè)類,并同時(shí)使用自己的配置類和超類的配置類:

// 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. 在子類中定義的配置類。

在使用上下文初始化程序的下一個(gè)示例中,通過使用BaseInitializerExtendedInitializer初始化ExtendedTestApplicationContext。但是請注意,初始化程序的調(diào)用順序取決于它們是實(shí)現(xiàn)Spring的Ordered接口還是以Spring的@Order注解或標(biāo)準(zhǔn)的@Priority注解進(jìn)行注釋。以下示例顯示了一個(gè)類如何擴(kuò)展另一個(gè)類并使用其自己的初始化程序和超類的初始化程序:

// 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. 子類中定義的初始化程序。

使用環(huán)境配置文件進(jìn)行上下文配置

Spring框架對環(huán)境和配置文件(又名“bean定義配置文件”)的概念提供了一流的支持,可以配置集成測試來激活針對各種測試場景的特定bean定義配置文件。這可以通過使用@ActiveProfiles注解測試類并提供在加載測試的ApplicationContext時(shí)應(yīng)激活的配置文件列表來實(shí)現(xiàn)。

你可以將@ActiveProfilesSmartContextLoader SPI的任何實(shí)現(xiàn)一起使用,但較早的ContextLoader SPI的實(shí)現(xiàn)不支持@ActiveProfiles。

考慮兩個(gè)帶有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
    }
}

運(yùn)行TransferServiceTest時(shí),會從類路徑根目錄中的app-config.xml配置文件中加載其ApplicationContext。如果檢查app-config.xml,可以看到accountRepository bean對dataSource bean有依賴性。但是,dataSource未被定義為頂級bean。相反,dataSource定義了三次:在生產(chǎn)配置文件中、在開發(fā)配置文件中以及在默認(rèn)配置文件中。

通過使用@ActiveProfiles(“dev”)注解TransferServiceTest,我們指示Spring TestContext 框架加載具有設(shè)置為{“dev”}的激活配置文件的ApplicationContext。結(jié)果,創(chuàng)建了一個(gè)嵌入式數(shù)據(jù)庫,并用測試數(shù)據(jù)填充了數(shù)據(jù)庫,并用對開發(fā)DataSource的引用來連接accountRepository bean。這可能是我們在集成測試中想要的。

有時(shí)將bean分配給默認(rèn)配置文件很有用。只有在沒有特別激活其他配置文件時(shí),才會包含缺省配置文件中的bean。你可以使用它來定義在應(yīng)用程序的默認(rèn)狀態(tài)中使用的后備bean。例如,你可以顯式提供devproduction的數(shù)據(jù)源,但是當(dāng)兩者都不處于活動狀態(tài)時(shí),將內(nèi)存中數(shù)據(jù)源定義為默認(rèn)值。

以下代碼清單演示了如何使用@Configuration類而不是XML實(shí)現(xiàn)相同的配置和集成測試:

@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配置分為四個(gè)獨(dú)立的@Configuration類:

  • ransferServiceConfig: 通過使用@Autowired進(jìn)行依賴項(xiàng)注入來獲取數(shù)據(jù)源。

  • StandaloneDataConfig: 為適合開發(fā)人員測試的嵌入式數(shù)據(jù)庫定義數(shù)據(jù)源。

  • JndiDataConfig: 定義在生產(chǎn)環(huán)境中從JNDI檢索的數(shù)據(jù)源。

  • DefaultDataConfig: 如果沒有配置文件處于激活狀態(tài),則為默認(rèn)的嵌入式數(shù)據(jù)庫定義一個(gè)數(shù)據(jù)源。

與基于XML的配置示例一樣,我們?nèi)匀皇褂?code>@ActiveProfiles("dev")注解TransferServiceTest,但是這次我們使用@ContextConfiguration注解指定所有四個(gè)配置類。測試類的主體本身保持完全不變。

在一個(gè)給定項(xiàng)目中,跨多個(gè)測試類使用一組配置文件是很常見的。因此,為避免@ActiveProfiles注解的重復(fù)聲明,可以在基類中聲明一次@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
}

此外,有時(shí)有必要以編程方式而不是聲明方式來解析測試的激活配置文件,例如,基于:

  • 當(dāng)前的操作系統(tǒng)。

  • 是否在持續(xù)集成構(gòu)建服務(wù)器上執(zhí)行測試。

  • 存在某些環(huán)境變量。

  • 自定義類級別注釋的存在。

  • 其他問題。

要以編程方式解析活動bean定義配置文件,可以實(shí)現(xiàn)自定義ActiveProfilesResolver并使用@ActiveProfilesresolver屬性對其進(jìn)行注冊。有關(guān)更多信息,請參見相應(yīng)的javadoc。下面的示例演示如何實(shí)現(xiàn)和注冊自定義的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框架對具有屬性源層次結(jié)構(gòu)的環(huán)境概念提供了一流的支持,你可以使用特定于測試的屬性源配置集成測試。與@Configuration類上使用的@PropertySource注解相反,可以在測試類上聲明@TestPropertySource注解,以聲明測試屬性文件或內(nèi)聯(lián)屬性的資源位置。這些測試屬性源被添加到環(huán)境中為帶注解的集成測試加載的ApplicationContextPropertySources集合中。

你可以將@TestPropertySourceSmartContextLoader SPI的任何實(shí)現(xiàn)一起使用,但是較早的ContextLoader SPI的實(shí)現(xiàn)不支持@TestPropertySource。

SmartContextLoader的實(shí)現(xiàn)可通過MergedContextConfiguration中的getPropertySourceLocations()getPropertySourceProperties()方法訪問合并的測試屬性源值。

聲明測試屬性源

你可以使用@TestPropertySource的locationvalue屬性來配置測試屬性文件。

支持傳統(tǒng)屬性文件格式和基于XML的屬性文件格式,例如: classpath:/com/example/test.propertiesfile:///path/to/file.xml。

每個(gè)路徑都被解析為Spring資源。普通路徑(例如 test.properties)被視為相對于定義測試類的程序包的類路徑資源。以斜杠開頭的路徑被視為絕對類路徑資源(例如:/org/example/test.xml)。通過使用指定的資源協(xié)議加載引用URL的路徑(例如,以classpath:、file:http:為前綴的路徑)。不允許使用資源位置通配符(例如* /.properties)每個(gè)位置都必須精確評估為一個(gè).properties.xml資源。

以下示例使用測試屬性文件:

@ContextConfiguration
@TestPropertySource("/test.properties") //1
class MyIntegrationTests {
    // class body...
}
  1. 指定具有絕對路徑的屬性文件。

你可以使用@TestPropertySourceproperties屬性,以鍵/值對的形式配置內(nèi)聯(lián)屬性,如下例所示。所有鍵值對都作為優(yōu)先級最高的單個(gè)測試PropertySource添加到封閉環(huán)境中。

鍵值對支持的語法與為Java屬性文件中的條目定義的語法相同:

  • key=value

  • key:value

  • key value

下面的示例設(shè)置兩個(gè)內(nèi)聯(lián)屬性:

@ContextConfiguration
@TestPropertySource(properties = {"timezone = GMT", "port: 4242"}) //1
class MyIntegrationTests {
    // class body...
}
  1. 通過使用鍵值語法的兩種變體來設(shè)置兩個(gè)屬性。

從Spring框架5.2開始,@TestPropertySource可以用作可重復(fù)注解。這意味著你可以在單個(gè)測試類上具有@TestPropertySource的多個(gè)聲明,其后的@TestPropertySource注解中的locationsproperties將覆蓋先前的@TestPropertySource注解中的locationsproperties。

此外,你可以在一個(gè)測試類上聲明多個(gè)組合注解,每個(gè)注解都用@TestPropertySource進(jìn)行元注解,所有這些@TestPropertySource聲明都將貢獻(xiàn)給你的測試屬性源。直接呈現(xiàn)的@TestPropertySource注解總是優(yōu)先于元呈現(xiàn)的@TestPropertySource注解。換句話說,直接存在的@TestPropertySource注解中的locationsproperties將覆蓋@TestPropertySource注解中用作元注解的locationsproperties

默認(rèn)屬性文件檢測

如果@TestPropertySource被聲明為空注解(即,沒有locationsproperties的顯式值),則嘗試檢測相對于聲明該注解的類的默認(rèn)屬性文件。例如,如果帶注解的測試類是com.example.MyTest,則相應(yīng)的對應(yīng)屬性文件是classpath:com/example/MyTest.properties。如果無法檢測到默認(rèn)值,則拋出IllegalStateException。

優(yōu)先順序

測試屬性的優(yōu)先級高于在操作系統(tǒng)環(huán)境、Java系統(tǒng)屬性或應(yīng)用程序通過使用@PropertySource聲明性地或以編程方式添加的屬性源中定義的屬性。因此,測試屬性可用于有選擇地覆蓋從系統(tǒng)和應(yīng)用程序?qū)傩栽醇虞d的屬性。此外,內(nèi)聯(lián)屬性優(yōu)先于從資源位置加載的屬性。但是請注意,通過@DynamicPropertySource注冊的屬性比通過@TestPropertySource加載的屬性具有更高的優(yōu)先級。

在下一個(gè)示例中,timezoneport屬性以及在/test.properties中定義的任何屬性都將覆蓋在系統(tǒng)和應(yīng)用程序?qū)傩栽粗卸x的同名屬性。此外,如果/test.properties文件定義了timezoneport屬性的條目,則這些條目將被使用properties屬性聲明的內(nèi)聯(lián)屬性所覆蓋。

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

繼承和覆蓋測試屬性源

@TestPropertySource支持布爾型的inheritLocationsinheritProperties屬性,它們表示屬性文件的資源位置和超類聲明的內(nèi)聯(lián)屬性是否應(yīng)該被繼承。這兩個(gè)標(biāo)志的默認(rèn)值為true。這意味著測試類將繼承任何超類聲明的位置和內(nèi)聯(lián)屬性。具體來說,測試類的位置和內(nèi)聯(lián)屬性附加到父類聲明的位置和內(nèi)聯(lián)屬性。因此,子類可以選擇擴(kuò)展位置和內(nèi)聯(lián)屬性。注意,后面出現(xiàn)的屬性會隱藏(即覆蓋)前面出現(xiàn)的同名屬性。此外,前面提到的優(yōu)先規(guī)則也適用于繼承的測試屬性源。

如果@TestPropertySource中的InheritLocationsInheritProperties屬性設(shè)置為false,則分別為測試類設(shè)置位置或內(nèi)聯(lián)屬性,并有效替換超類定義的配置。

在下一個(gè)示例中,BaseTestApplicationContext是通過只使用base加載的。屬性文件作為測試屬性源。相反,ExtendedTestApplicationContext是通過使用base加載的屬性和擴(kuò)展。屬性文件作為測試屬性源位置。下面的示例演示如何使用屬性文件在子類及其超類中定義屬性:

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

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

在下一個(gè)示例中,僅使用內(nèi)聯(lián)的key1屬性來加載BaseTestApplicationContext。相反,使用內(nèi)聯(lián)的key1key2屬性來加載ExtendedTestApplicationContext。下面的示例演示如何通過使用內(nèi)聯(lián)屬性在子類及其父類中定義屬性:

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

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

通過動態(tài)屬性源配置上下文

從Spring框架5.2.5開始,TestContext框架通過@DynamicPropertySource注解提供對動態(tài)屬性的支持。此注解可用于需要向?yàn)榧蓽y試加載的ApplicationContext的環(huán)境中的PropertySources集添加帶有動態(tài)值的屬性的集成測試。

@DynamicPropertySource注解及其支持的基礎(chǔ)結(jié)構(gòu)最初旨在使基于Testcontainers的測試中的屬性易于暴露于Spring集成測試。但是,此功能還可以用于其生命周期在測試的ApplicationContext之外維護(hù)的任何形式的外部資源。

與在類級別應(yīng)用@TestPropertySource注解相反,@DynamicPropertySource必須應(yīng)用于接受單個(gè)DynamicPropertyRegistry參數(shù)的靜態(tài)方法,該參數(shù)用于向環(huán)境添加名稱/值對。值是動態(tài)的,并通過Supplier提供,只有在解析屬性時(shí)才調(diào)用Supplier。通常,方法引用被用來提供值,如下面的例子所示,它使用Testcontainers項(xiàng)目在Spring ApplicationContext之外管理一個(gè)Redis容器。通過redis.hostredis.port屬性,測試的ApplicationContext中的組件可以使用托管Redis容器的IP地址和端口。這些屬性可以通過Spring的環(huán)境抽象訪問,或者直接注入到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 ...

}

優(yōu)先順序

動態(tài)屬性的優(yōu)先級高于@TestPropertySource、操作系統(tǒng)的環(huán)境、Java系統(tǒng)屬性或應(yīng)用程序通過@PropertySource聲明性地或以編程方式添加的屬性源中加載的屬性。因此,動態(tài)屬性可用于有選擇地覆蓋通過@TestPropertySource、系統(tǒng)屬性源和應(yīng)用程序?qū)傩栽醇虞d的屬性。

加載WebApplicationContext

若要指示TestContext框架加載WebApplicationContext而不是標(biāo)準(zhǔn)ApplicationContext,可以使用@WebAppConfiguration注解各自的測試類。

測試類上@WebAppConfiguration的存在指示TestContext框架(TCF)應(yīng)該為集成測試加載WebApplicationContext(WAC)。TCF在后臺確保創(chuàng)建了MockServletContext并將其提供給測試的WAC。默認(rèn)情況下,你的MockServletContext的基本資源路徑設(shè)置為src/main/webapp。這被解釋為相對于JVM根目錄的路徑(通常是項(xiàng)目的路徑)。如果你熟悉Maven項(xiàng)目中Web應(yīng)用程序的目錄結(jié)構(gòu),則知道src/main/webapp是WAR根目錄的默認(rèn)位置。如果需要覆蓋此默認(rèn)值,則可以提供@WebAppConfiguration注解的替換路徑(例如,@WebAppConfiguration(“src/test/webapp”))。如果你希望從類路徑而不是文件系統(tǒng)中引用基本資源路徑,則可以使用Spring的classpath:前綴。

請注意,Spring對WebApplicationContext實(shí)現(xiàn)的測試支持與其對標(biāo)準(zhǔn)ApplicationContext實(shí)現(xiàn)的支持相當(dāng)。使用WebApplicationContext進(jìn)行測試時(shí),可以使用@ContextConfiguration聲明XML配置文件、Groovy腳本或@Configuration類。你還可以自由地使用任何其他測試注解,如@ActiveProfiles、@Testexecutionlistener、@Sql、@Rollback和其他。

本節(jié)的其余示例展示了加載WebApplicationContext的一些不同配置選項(xiàng)。以下示例顯示了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注解測試類而未指定資源基本路徑,則資源路徑實(shí)際上默認(rèn)為file:src/main/webapp。同樣,如果在聲明@ContextConfiguration時(shí)未指定資源位置、組件類或上下文初始化程序,則Spring會嘗試使用約定(也就是說,WacTests-context.xmlWacTests類或靜態(tài)嵌套@Configuration類位于同一包中)。

以下示例顯示如何使用@WebAppConfiguration顯式聲明資源基本路徑和使用@ContextConfiguration顯式聲明XML資源位置:

@ExtendWith(SpringExtension.class)

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

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

這里要注意的重要一點(diǎn)是具有這兩個(gè)注解的路徑的語義不同。默認(rèn)情況下,@ WebAppConfiguration資源路徑基于文件系統(tǒng),而@ContextConfiguration資源位置基于類路徑。下面的示例顯示,我們可以通過指定Spring資源前綴來覆蓋兩個(gè)注解的默認(rèn)資源語義:

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

將本示例中的注解與上一個(gè)示例進(jìn)行對比。

使用Web Mock工作

為了提供全面的Web測試支持,TestContext框架具有默認(rèn)啟用的ServletTestExecutionListener。在針對WebApplicationContext進(jìn)行測試時(shí),此TestExecutionListener會在每個(gè)測試方法之前使用Spring Web的RequestContextHolder來設(shè)置默認(rèn)的線程本地狀態(tài),并根據(jù)通過@WebAppConfiguration配置的基本資源路徑創(chuàng)建MockHttpServletRequestMockHttpServletResponseServletWebRequest。

ServletTestExecutionListener還確??梢詫?code>MockHttpServletResponse和ServletWebRequest注入到測試實(shí)例中,并且一旦測試完成,它將清除線程本地狀態(tài)。

一旦為測試加載了WebApplicationContext,你可能會發(fā)現(xiàn)你需要與Web模擬進(jìn)行交互,例如,在調(diào)用Web組件之后設(shè)置測試fixture或執(zhí)行斷言。以下示例顯示可以將哪些模擬自動裝配到你的測試實(shí)例。請注意,WebApplicationContextMockServletContext都緩存在測試套件中,而其他模擬則由ServletTestExecutionListener針對每個(gè)測試方法進(jìn)行管理。

@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),該上下文將被緩存并重新用于在同一測試套件中聲明相同唯一上下文配置的所有后續(xù)測試。要了解緩存的工作原理,重要的是要了解unique測試套件的含義。

可以通過用于加載它的配置參數(shù)的組合來唯一標(biāo)識ApplicationContext。因此,使用配置參數(shù)的唯一組合來生成一個(gè)鍵,在該鍵下緩存上下文。TestContext框架使用以下配置參數(shù)來構(gòu)建上下文緩存鍵:

  • 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框架將加載相應(yīng)的ApplicationContext并將其存儲在靜態(tài)上下文緩存中僅基于那些位置的key下。因此,如果TestClassB還為其位置(通過繼承顯式或隱式)定義了{“app-config.xml”,“test-config.xml”},但未定義@WebAppConfiguration、不同的ContextLoader、不同的激活配置文件、不同的上下文初始化程序、不同的測試屬性源或不同的父上下文,則兩個(gè)測試類將共享相同的ApplicationContext。這意味著(每個(gè)測試套件)僅需加載一次加載應(yīng)用程序上下文的設(shè)置成本,并且隨后的測試執(zhí)行要快得多。

測試套件和分支流程

Spring TestContext框架將應(yīng)用程序上下文存儲在靜態(tài)緩存中。這意味著上下文實(shí)際上是存儲在靜態(tài)變量中的。換句話說,如果測試是在單獨(dú)的進(jìn)程中執(zhí)行的,則在每個(gè)測試執(zhí)行之間都會清除靜態(tài)緩存,從而有效地禁用了緩存機(jī)制。

為了從緩存機(jī)制中受益,所有測試必須在同一進(jìn)程或測試套件中運(yùn)行。這可以通過在IDE中以組的形式執(zhí)行所有測試來實(shí)現(xiàn)。同樣,在使用諸如Ant、Maven或Gradle之類的構(gòu)建框架執(zhí)行測試時(shí),確保該構(gòu)建框架不會在測試之間進(jìn)行派生(fork多個(gè)進(jìn)程)很重要。例如,如果將Maven Surefire插件的forkMode設(shè)置為always或pertest,則TestContext框架將無法在測試類之間緩存應(yīng)用程序上下文,因此,構(gòu)建過程的運(yùn)行速度將大大降低。

上下文緩存的大小以默認(rèn)的最大32為界。只要達(dá)到最大大小,就會使用最近最少使用(LRU)驅(qū)逐策略來驅(qū)逐和關(guān)閉舊的上下文。你可以通過設(shè)置名為spring.test.context.cache.maxSize的JVM系統(tǒng)屬性,從命令行或構(gòu)建腳本中配置最大大小。或者,你可以使用SpringProperties API以編程方式設(shè)置相同的屬性。

由于在給定的測試套件中加載大量的應(yīng)用程序上下文會導(dǎo)致該套件花費(fèi)不必要的長時(shí)間來執(zhí)行,因此準(zhǔn)確地知道已加載和緩存了多少個(gè)上下文通常是有益的。要查看基礎(chǔ)上下文緩存的統(tǒng)計(jì)信息,可以將org.springframework.test.context.cache日志記錄類別的日志級別設(shè)置為DEBUG

在不太可能的情況下,測試破壞了應(yīng)用程序上下文并需要重新加載(例如,通過修改bean定義或應(yīng)用程序?qū)ο蟮臓顟B(tài)),你可以使用@DirtiesContext注解測試類或測試方法(請參閱@DirtiesContext中對@DirtiesContext的討論)。這指示Spring在運(yùn)行需要相同應(yīng)用程序上下文的下一個(gè)測試之前,從緩存中刪除上下文并重建應(yīng)用程序上下文。請注意,默認(rèn)情況下啟用的DirtiesContextBeforeModesTestExecutionListenerDirtiesContextTestExecutionListener提供了對@DirtiesContext注解的支持。

上下文層級

在編寫依賴于已加載的Spring ApplicationContext的集成測試時(shí),通常足以針對單個(gè)上下文進(jìn)行測試。但是,有時(shí)需要對ApplicationContext實(shí)例的層次結(jié)構(gòu)進(jìn)行測試是有益的,甚至是必要的。例如,如果你正在開發(fā)Spring MVC Web應(yīng)用程序,則通常由Spring的ContextLoaderListener加載根WebApplicationContext,由Spring的DispatcherServlet加載子WebApplicationContext。這將導(dǎo)致父子上下文層次結(jié)構(gòu),其中共享組件和基礎(chǔ)設(shè)施配置在根上下文中聲明,并由特定于web的組件在子上下文中使用。在Spring Batch應(yīng)用程序中可以找到另一個(gè)用例,在該應(yīng)用程序中,你通常具有一個(gè)父上下文,該上下文為共享批處理基礎(chǔ)結(jié)構(gòu)提供配置,而子上下文則為特定批處理作業(yè)的配置提供配置。

你可以通過在單個(gè)測試類上或在測試類層次結(jié)構(gòu)中使用@ContextHierarchy注解聲明上下文配置來編寫使用上下文層次結(jié)構(gòu)的集成測試。如果在測試類層次結(jié)構(gòu)中的多個(gè)類上聲明了上下文層次結(jié)構(gòu),則還可以合并或覆蓋上下文層次結(jié)構(gòu)中特定命名級別的上下文配置。合并層次結(jié)構(gòu)中給定級別的配置時(shí),配置資源類型(即XML配置文件或組件類)必須一致。否則,在使用不同資源類型配置的上下文層次結(jié)構(gòu)中具有不同級別是完全可以接受的。

本節(jié)中其余的基于JUnit Jupiter的示例顯示了需要使用上下文層次結(jié)構(gòu)的集成測試的常見配置方案。

具有上下文層次結(jié)構(gòu)的單個(gè)測試類

ControllerIntegrationTests通過聲明一個(gè)上下文層次結(jié)構(gòu)來代表Spring MVC Web應(yīng)用程序的典型集成測試場景,該上下文層次結(jié)構(gòu)包含兩個(gè)級別,一個(gè)層次用于根WebApplicationContext(通過使用TestAppConfig @Configuration類加載),一個(gè)層次用于調(diào)度程序Servlet WebApplicationContext(通過使用WebConfig @Configuration類加載)。自動裝配到測試實(shí)例的WebApplicationContext是用于子上下文(即,層次結(jié)構(gòu)中的最低上下文)的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

具有隱式父上下文的類層次結(jié)構(gòu)

本示例中的測試類在測試類層次結(jié)構(gòu)中定義了上下文層次結(jié)構(gòu)。AbstractWebTests在Spring驅(qū)動的Web應(yīng)用程序中聲明根WebApplicationContext的配置。但是請注意,AbstractWebTests不會聲明@ContextHierarchy。因此,AbstractWebTests的子類可以選擇參與上下文層次結(jié)構(gòu)或遵循@ContextConfiguration的標(biāo)準(zhǔn)語義。SoapWebServiceTestsRestWebServiceTests都擴(kuò)展了AbstractWebTests并使用@ContextHierarchy定義了上下文層次結(jié)構(gòu)。結(jié)果是,加載了三個(gè)應(yīng)用程序上下文(每個(gè)@ContextConfiguration聲明一個(gè)),并且基于AbstractWebTests中的配置加載的應(yīng)用程序上下文被設(shè)置為具體子類加載的每個(gè)上下文的父上下文。

@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

合并上下文層次結(jié)構(gòu)配置的類層次結(jié)構(gòu)

此示例中的類顯示了使用命名層次結(jié)構(gòu)級別的目的,以及合并上下文層次結(jié)構(gòu)中特定級別的配置。BaseTests在層次結(jié)構(gòu)中定義了兩個(gè)級別,parentchildExtendedTests擴(kuò)展BaseTests并指示Spring TestContext 框架合并子層次結(jié)構(gòu)級別的上下文配置,方法是<u>確保在@ContextConfiguration的name屬性中聲明的名稱均為子元素</u>。結(jié)果是加載了三個(gè)應(yīng)用程序上下文:一個(gè)用于/app-config.xml、一個(gè)用于/user-config.xml、一個(gè)用于{/user-config.xml/order-config.xml} 。與前面的示例一樣,將從/app-config.xml加載的應(yīng)用程序上下文設(shè)置為從/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

具有覆蓋的上下文層次結(jié)構(gòu)配置的類層次結(jié)構(gòu)

與前面的示例相反,此示例演示了如何通過將@ContextConfiguration中的InheritLocations標(biāo)志設(shè)置為false來覆蓋上下文層次結(jié)構(gòu)中給定命名級別的配置。因此,ExtendedTests的應(yīng)用程序上下文僅從/test-user-config.xml加載,并且其父級設(shè)置為從/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 {}

清除上下文層次結(jié)構(gòu)中的上下文

如果你在一個(gè)測試中使用@DirtiesContext,該測試的上下文被配置為上下文層次結(jié)構(gòu)的一部分,那么你可以使用hierarchyMode標(biāo)志來控制如何清除上下文緩存。有關(guān)更多詳細(xì)信息,請參見Spring Testing Annotations中的@DirtiesContext和@DirtiesContext javadoc的討論。

參考代碼:org.liyong.test.annotation.test.spring.ExtendedTests1

3.5.6 測試裝置的依賴注入

當(dāng)使用DependencyInjectionTestExecutionListener(默認(rèn)配置)時(shí),測試實(shí)例的依賴項(xiàng)是從使用@ContextConfiguration或相關(guān)注解配置應(yīng)用程序上下文中的bean注入的。你可以使用setter注入、字段注入、或同時(shí)使用這兩種方法,具體取決于你選擇的注解以及是否將它們放在setter方法或字段上。如果你使用的是JUnit Jupiter,則還可以選擇使用構(gòu)造函數(shù)注入(請參閱帶有SpringExtension的依賴注入)。為了與Spring基于注解的注入支持保持一致,你還可以將Spring的@Autowired注解或JSR-330中的@Inject注解用于字段注入和setter 注入。

對于JUnit Jupiter以外的測試框架,TestContext框架不參與測試類的實(shí)例化。因此,將@Autowired@Inject用于構(gòu)造函數(shù)對測試類無效。

盡管在生產(chǎn)代碼中不鼓勵(lì)使用字段注入,但是在測試代碼中字段注入實(shí)際上是很自然的。理由是你永遠(yuǎn)不會直接實(shí)例化測試類。因此,不需要在測試類上調(diào)用公共構(gòu)造函數(shù)或setter方法。

因?yàn)?code>@Autowired用于按類型執(zhí)行自動裝配,所以如果你具有多個(gè)相同類型的Bean定義,那么對于那些特定的Bean,你將不能依靠這種方法。在這種情況下,可以將@Autowired@Qualifier結(jié)合使用。你也可以選擇將@Inject@Named結(jié)合使用?;蛘撸绻愕臏y試類可以訪問其ApplicationContext,則可以通過使用(例如)對applicationContext.getBean(“ titleRepository“,TitleRepository.class)的調(diào)用來執(zhí)行顯式查找。

如果你不希望將依賴項(xiàng)注入應(yīng)用于測試實(shí)例,請不要使用@Autowired@Inject注解字段或設(shè)置器方法?;蛘撸憧梢酝ㄟ^顯式地用@TestExecutionListeners配置你的類,并從監(jiān)聽器列表中忽略DependencyInjectionTestExecutionListener.class來禁用依賴注入。

考慮測試HibernateTitleRepository類的場景,如目標(biāo)部分所述。接下來的兩個(gè)代碼清單演示了@Autowired在字段和setter方法上的用法。在所有示例代碼清單之后顯示了應(yīng)用程序上下文配置。

以下代碼清單中的依賴項(xiàng)注入行為并非特定于JUnit Jupiter。相同的DI技術(shù)可以與任何受支持的測試框架結(jié)合使用。

以下示例對靜態(tài)斷言方法(例如assertNotNull())進(jìn)行了調(diào)用,但沒有在聲明前添加Assertions。在這種情況下,假定該方法是通過示例中未顯示的import static聲明正確導(dǎo)入的。

第一個(gè)代碼清單顯示了使用@Autowired進(jìn)行字段注入的測試類的基于JUnit Jupiter的實(shí)現(xiàn):

@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進(jìn)行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提供的測試基類擴(kuò)展而來的,而該基類恰巧在其setter方法之一上使用@Autowired,則可能在應(yīng)用程序上下文中定義了多個(gè)受影響類型的Bean(例如,多個(gè)DataSource Bean)。在這種情況下,你可以覆蓋setter方法,并使用@Qualifier注解指示特定的目標(biāo)bean,如下所示(但請確保也委托給超類中的重寫方法):

// ...

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

// ...

指定的限定符值指示要注入的特定DataSource Bean,從而將類型匹配的范圍縮小到特定Bean。其值與相應(yīng)的<bean>定義中的<qualifier>聲明匹配。Bean名稱用作后備限定符值,因此你也可以在該名稱中有效地指向特定的Bean(如先前所示,假設(shè)myDataSource是Bean ID)。

到此,相信大家對“怎么用XML資源配置上下文”有了更深的了解,不妨來實(shí)際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

xml
AI