天天看點

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

3.5.5 上下文管理

每個

TestContext

為其負責的測試執行個體提供上下文管理和緩存支援。測試執行個體不會自動接收對配置的

ApplicationContext

的通路。但是,如果測試類實作

ApplicationContextAware

接口,則将對

ApplicationContext

的引用提供給測試執行個體。請注意,

AbstractJUnit4SpringContextTests

AbstractTestNGSpringContextTests

實作了

ApplicationContextAware

,是以可以自動提供對

ApplicationContext

的通路。

@Autowired

ApplicationContext

作為實作

ApplicationContextAware

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

setter

方法上的

@Autowired

注解為測試類注入應用程式上下文,如以下示例所示:
@SpringJUnitConfig
class MyTest {

 @Autowired //1
 ApplicationContext applicationContext;

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

    ApplicationContext

同樣,如果将測試配置為加載

WebApplicationContext

,則可以将Web應用程式上下文注入到測試中,如下所示:
@SpringJUnitWebConfig //1
class MyWebAppTest {

    @Autowired //2
    WebApplicationContext wac;

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

    WebApplicationContext

  2. WebApplicationContext

使用

@Autowired

的依賴關系注入是

DependencyInjectionTestExecutionListener

提供的,它是預設配置的( 參見測試裝置的依賴注入 )。

TestContext

架構的測試類不需要擴充任何特定的類或實作特定的接口來配置其應用程式上下文。而是通過在類級别聲明

@ContextConfiguration

注解來實作配置。如果你的測試類未明确聲明應用程式上下文資源位置或元件類,則配置的

ContextLoader

将确定如何從預設位置或預設配置類加載上下文。除了上下文資源位置群組件類之外,還可以通過應用程式上下文初始化程式配置應用程式上下文。

以下各節說明如何使用Spring的

@ContextConfiguration

注解通過XML配置檔案、

Groovy

腳本、元件類(通常為

@Configuration

類)或上下文初始化器來配置測試

ApplicationContext

。另外,你可以為進階用例實作和配置自己的自定義

SmartContextLoader

若要使用XML配置檔案為測試加載

ApplicationContext

,請使用

@ContextConfiguration

注解測試類,并使用包含XML配置中繼資料的資源位置的數組配置

locations

屬性。簡單路徑或相對路徑(例如

context.xml

)被視為相對于定義測試類的程式包的類路徑資源。以斜杠開頭的路徑被視為絕對類路徑位置(例如:

/org/example/config.xml

)。照原樣使用表示資源URL的路徑(即以

classpath:

file:

http:

等開頭的路徑)。

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

    屬性設定為XML檔案清單。

@ContextConfiguration

通過标準Java值屬性為

locations

屬性支援别名。是以,如果不需要在

@ContextConfiguration

中聲明其他屬性,你可以使用以下示例中示範的格式,省略

locations

屬性名稱的聲明并聲明資源位置。

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

    location

    屬性指定XML檔案。

如果你從

@ContextConfiguration

注解中省略了位置和值屬性,則

TestContext

架構将嘗試檢測預設的XML資源位置。具體而言,

GenericXmlContextLoader

GenericXmlWebContextLoader

根據測試類的名稱檢測預設位置。如果你的類名為

com.example.MyTest

GenericXmlContextLoader

classpath:com/example/MyTest-context.xml

加載應用程式上下文。以下示例顯示了如何執行此操作:

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

要通過使用

Groovy Bean定義DSL

的Groovy腳本為測試加載

ApplicationContext

,可以使用

@ContextConfiguration

注解測試類,并使用包含Groovy腳本資源位置的數組配置

location

value

屬性。Groovy腳本的資源查找語義與針對

XML配置檔案

描述的語義相同。

激活Groovy腳本支援

如果類路徑中有Groovy,那麼就會自動啟用使用Groovy腳本在Spring

TestContext

架構中加載

ApplicationContext

的支援。

下面的示例顯示如何指定Groovy配置檔案:

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

@ContextConfiguration

注解中省略了

location

value

屬性,則

TestContext

架構将嘗試檢測預設的Groovy腳本。具體來說,

GenericGroovyXmlContextLoader

GenericGroovyXmlWebContextLoader

com.example.MyTest

則Groovy上下文加載器将從

classpath:com/example/MyTestContext.groovy

加載應用程式上下文。下面的示例示範如何使用預設值:

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

同時聲明XML配置和Groovy腳本

你可以使用

@ContextConfiguration

location

value

屬性同時聲明XML配置檔案和Groovy腳本。如果到配置的資源位置的路徑以

.xml

結尾,則使用

XmlBeanDefinitionReader

加載該路徑。否則,将使用

GroovyBeanDefinitionReader

加載它。

以下清單顯示了如何在內建測試中将兩者結合起來:

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

要使用元件類(請參見

基于Java的容器配置

)為測試加載

ApplicationContext

@ContextConfiguration

注解測試類,并使用包含對元件類的引用的數組來配置

classes

屬性。以下示例顯示了如何執行此操作:

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

元件類

術語

元件類

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

    注解的類。
  • 元件(即,用

    @Component

    @Service

    @Repository

    或其他構造型注解注釋的類)。
  • 與JSR-330相容的類,該類使用

    javax.inject

    注解進行了注釋。
  • 包含

    @Bean

    方法的任何類。
  • 打算注冊為Spring元件的任何其他類(即

    ApplicationContext

    中的Spring bean),可能利用單個自動構造函數的自動裝配而無需使用Spring注解。
有關元件類的配置和語義的更多資訊,請參見 @Configuration @Bean 的javadoc,尤其要注意

@Bean

Lite模式的讨論。

@ContextConfiguration

classes

TestContext

架構将嘗試檢測預設配置類的存在。具體來說,

AnnotationConfigContextLoader

AnnotationConfigWebContextLoader

檢測到滿足配置類實作要求的測試類的所有靜态嵌套類,如

javadoc中所指定。請注意,配置類的名稱是任意的。另外,如果需要,一個測試類可以包含多個靜态嵌套配制類。在以下示例中,

OrderServiceTest

類聲明一個名為

Config

的靜态嵌套配置類,該配置類将自動用于為測試類加載

ApplicationContext

@SpringJUnitConfig //1
// ApplicationContext将從内部潛逃靜态累加載
class OrderServiceTest {

    @Configuration
    static class Config {

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

    @Autowired
    OrderService orderService;

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

}           
  1. 從嵌套的Config類加載配置資訊。

有時可能需要混合使用XML配置檔案、Groovy腳本群組件類(通常為

@Configuration

類)來為測試配置

ApplicationContext

。如果在生産中使用XML配置,則可以決定要使用

@Configuration

類為測試配置特定的Spring托管元件,反之亦然。

此外,某些第三方架構(例如Spring Boot)提供了一流的支援,可以同時從不同類型的資源(例如XML配置檔案、Groovy腳本和

@Configuration

類)中加載

ApplicationContext

。過去,Spring架構不支援此标準部署。是以,Spring架構在

spring-test

子產品中提供的大多數

SmartContextLoader

實作對于每個測試上下文僅支援一種資源類型。但是,這并不意味着你不能同時使用兩者。通用規則的一個例外是

GenericGroovyXmlContextLoader

GenericGroovyXmlWebContextLoader

同時支援XML配置檔案和Groovy腳本。此外,第三方架構可以選擇通過

@ContextConfiguration

支援位置和類的聲明,并且,借助

TestContext

架構中的标準測試支援,你可以選擇以下選項。

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

@Configuration

類的配置測試,則必須選擇一個作為入口點,并且其中一個必須包含或導入另一個。例如,在XML或Groovy腳本中,可以通過使用元件掃描或将它們定義為普通的Spring bean來包括

@Configuration

類,而在

@Configuration

類中,可以使用

@ImportResource

導入XML配置檔案或Groovy腳本。請注意,此行為在語義上等同于你在生産環境中配置應用程式的方式:在生産配置中,你定義了一組XML或Groovy資源位置或一組

@Configuration

類,從中加載了生産

ApplicationContext

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

若要使用上下文初始化程式為你的測試配置

ApplicationContext

@ContextConfiguration

注解測試類,并使用包含對實作

ApplicationContextInitializer

的類的引用的數組配置初始化程式屬性。然後,使用聲明的上下文初始值設定項來初始化為測試加載的

ConfigurableApplicationContext

。請注意,每個聲明的初始化程式支援的具體

ConfigurableApplicationContext

類型必須與使用中的

SmartContextLoader

建立的

ApplicationContext

類型(通常是

GenericApplicationContext

)相容。此外,初始化程式的調用順序取決于它們是實作Spring的

Ordered

接口還是以Spring的

@Order

注解或标準的

@Priority

注解進行注釋。下面的示例示範如何使用初始化程式:

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

你還可以完全省略

@ContextConfiguration

中的XML配置檔案、Groovy腳本或元件類的聲明,而僅聲明

ApplicationContextInitializer

類,然後這些類負責在上下文中注冊Bean(例如,通過程式設計方式從XML檔案加載Bean定義)或配置類。以下示例顯示了如何執行此操作:

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

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

@ContextConfiguration

支援

boolean

inheritLocations

inheritinitialalizer

屬性,它們表示是否應該繼承由超類聲明的資源位置或元件類和上下文初始化器。這兩個标志的預設值為

true

。這意味着測試類将繼承資源位置或元件類以及任何超類申明的上下文初始化器。具體來說,将測試類的資源位置或元件類附加到由超類申明的資源位置或帶注解的類的清單中。同樣,将給定測試類的初始化程式添加到由測試超類定義的初始化程式集。是以,子類可以選擇擴充資源位置、元件類或上下文初始化程式。

如果

@ContextConfiguration

中的

inheritLocations

inheritInitializers

屬性被設定為

false

,則測試類的資源位置或元件類和上下文初始化器将分别有效地替代超類定義的配置。

在下一個使用XML資源位置的示例中,從

Base-config.xml

Extended-config.xml依

次加載

ExtendedContext

ApplicationContext

。是以,

extended-config.xml

中定義的Bean可以覆寫(即替換)

base-config.xml

中定義的那些。以下示例顯示了一個類如何擴充另一個類并使用其自己的配置檔案和超類的配置檔案:

@ExtendWith(SpringExtension.class)
// ApplicationContext将從類路徑根目錄加載"/base-config.xml"
@ContextConfiguration("/base-config.xml") //1
class BaseTest {
    // class body...
}

// ApplicationContext将從類路徑根目錄加載"/base-config.xml" 和
// "/extended-config.xml"
@ContextConfiguration("/extended-config.xml") //2
class ExtendedTest extends BaseTest {
    // class body...
}           
  1. 在超類中定義的配置檔案
  2. 子類中定義的配置檔案。

同樣,在下一個使用元件類的示例中,從

BaseConfig

ExtendedConfig

類按該順序加載

ExtendedTest

ApplicationContext

。是以,在

ExtendedConfig

中定義的Bean可以覆寫(即替換)在

BaseConfig

中定義的Bean。下面的示例顯示一個類如何擴充另一個類,并同時使用自己的配置類和超類的配置類:

// ApplicationContext從BaseConfig加載
@SpringJUnitConfig(BaseConfig.class) //1
class BaseTest {
    // class body...
}

// ApplicationContext将從BaseConfig和ExtendedConfig加載
@SpringJUnitConfig(ExtendedConfig.class) //2
class ExtendedTest extends BaseTest {
    // class body...
}           
  1. 在超類中定義的配置類
  2. 在子類中定義的配置類。

在使用上下文初始化程式的下一個示例中,通過使用

BaseInitializer

ExtendedInitializer

初始化

ExtendedTest

ApplicationContext

。但是請注意,初始化程式的調用順序取決于它們是實作Spring的

Ordered

@Order

@Priority

注解進行注釋。以下示例顯示了一個類如何擴充另一個類并使用其自己的初始化程式和超類的初始化程式:

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

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

使用環境配置檔案進行上下文配置

Spring架構對環境和配置檔案(又名“bean定義配置檔案”)的概念提供了一流的支援,可以配置內建測試來激活針對各種測試場景的特定bean定義配置檔案。這可以通過使用

@ActiveProfiles

注解測試類并提供在加載測試的

ApplicationContext

時應激活的配置檔案清單來實作。

你可以将

@ActiveProfiles

SmartContextLoader

SPI的任何實作一起使用,但較早的

ContextLoader

SPI的實作不支援

@ActiveProfiles

考慮兩個帶有XML配置和

@Configuration

類的示例:

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

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

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

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

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

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

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

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

    @Autowired
    TransferService transferService;

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

運作

TransferServiceTest

時,會從類路徑根目錄中的

app-config.xml

配置檔案中加載其

ApplicationContext

。如果檢查

app-config.xml

,可以看到accountRepository bean對

dataSource

bean有依賴性。但是,

dataSource

未被定義為頂級bean。相反,

dataSource

定義了三次:在生産配置檔案中、在開發配置檔案中以及在預設配置檔案中。

通過使用

@ActiveProfiles(“dev”)

注解

TransferServiceTest

,我們訓示Spring

TestContext

架構加載具有設定為

{“dev”}

的激活配置檔案的

ApplicationContext

。結果,建立了一個嵌入式資料庫,并用測試資料填充了資料庫,并用對開發

DataSource

的引用來連接配接

accountRepository

bean。這可能是我們在內建測試中想要的。

有時将bean配置設定給預設配置檔案很有用。隻有在沒有特别激活其他配置檔案時,才會包含預設配置檔案中的bean。你可以使用它來定義在應用程式的預設狀态中使用的後備bean。例如,你可以顯式提供

dev

production

的資料源,但是當兩者都不處于活動狀态時,将記憶體中資料源定義為預設值。

以下代碼清單示範了如何使用

@Configuration

類而不是XML實作相同的配置和內建測試:

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

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

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

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

    @Autowired DataSource dataSource;

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

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

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

    @Autowired
    TransferService transferService;

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

在此變體中,我們将XML配置分為四個獨立的

@Configuration

類:

  • ransferServiceConfig

    : 通過使用

    @Autowired

    進行依賴項注入來擷取資料源。
  • StandaloneDataConfig

    : 為适合開發人員測試的嵌入式資料庫定義資料源。
  • JndiDataConfig

    : 定義在生産環境中從JNDI檢索的資料源。
  • DefaultDataConfig

    : 如果沒有配置檔案處于激活狀态,則為預設的嵌入式資料庫定義一個資料源。

與基于XML的配置示例一樣,我們仍然使用

@ActiveProfiles("dev")

TransferServiceTest

,但是這次我們使用

@ContextConfiguration

注解指定所有四個配置類。測試類的主體本身保持完全不變。

在一個給定項目中,跨多個測試類使用一組配置檔案是很常見的。是以,為避免

@ActiveProfiles

注解的重複聲明,可以在基類中聲明一次

@ActiveProfiles

,子類會自動從基類繼承

@ActiveProfiles

配置。在以下示例中,

@ActiveProfiles

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

AbstractIntegrationTest

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

    @Autowired
    TransferService transferService;

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

@ActiveProfiles

還支援可用于禁用激活配置檔案的繼承的

InheritedProfiles

屬性,如以下示例所示:

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

此外,有時有必要以程式設計方式而不是聲明方式來解析測試的激活配置檔案,例如,基于:

  • 目前的作業系統。
  • 是否在持續內建建構伺服器上執行測試。
  • 存在某些環境變量。
  • 自定義類級别注釋的存在。
  • 其他問題。

要以程式設計方式解析活動bean定義配置檔案,可以實作自定義

ActiveProfilesResolver

并使用

@ActiveProfiles

resolver

屬性對其進行注冊。有關更多資訊,請參見相應的

javadoc

。下面的示例示範如何實作和注冊自定義的

OperatingSystemActiveProfilesResolver

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

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

Spring架構對具有屬性源層次結構的環境概念提供了一流的支援,你可以使用特定于測試的屬性源配置內建測試。與

@Configuration

類上使用的

@PropertySource

注解相反,可以在測試類上聲明

@TestPropertySource

注解,以聲明測試屬性檔案或内聯屬性的資源位置。這些測試屬性源被添加到環境中為帶注解的內建測試加載的

ApplicationContext

PropertySources

集合中。

@TestPropertySource

SmartContextLoader

SPI的任何實作一起使用,但是較早的

ContextLoader

@TestPropertySource

SmartContextLoader

的實作可通過

MergedContextConfiguration

getPropertySourceLocations()

getPropertySourceProperties()

方法通路合并的測試屬性源值。

聲明測試屬性源

@TestPropertySource的location

value

屬性來配置測試屬性檔案。

支援傳統屬性檔案格式和基于XML的屬性檔案格式,例如:

classpath:/com/example/test.properties

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

每個路徑都被解析為Spring資源。普通路徑(例如

test.properties

)被視為相對于定義測試類的程式包的類路徑資源。以斜杠開頭的路徑被視為絕對類路徑資源(例如:

/org/example/test.xml

)。通過使用指定的資源協定加載引用URL的路徑(例如,以

classpath:

file:

http:

為字首的路徑)。不允許使用資源位置通配符(例如

* /.properties

)每個位置都必須精确評估為一個

.properties

.xml

資源。

以下示例使用測試屬性檔案:

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

@TestPropertySource

properties

屬性,以鍵/值對的形式配置内聯屬性,如下例所示。所有鍵值對都作為優先級最高的單個測試

PropertySource

添加到封閉環境中。

鍵值對支援的文法與為Java屬性檔案中的條目定義的文法相同:

  • key=value

  • key:value

  • key value

下面的示例設定兩個内聯屬性:

@ContextConfiguration
@TestPropertySource(properties = {"timezone = GMT", "port: 4242"}) //1
class MyIntegrationTests {
    // class body...
}
           
  1. 通過使用鍵值文法的兩種變體來設定兩個屬性。
從Spring架構5.2開始,

@TestPropertySource

可以用作可重複注解。這意味着你可以在單個測試類上具有

@TestPropertySource

的多個聲明,其後的

@TestPropertySource

注解中的

locations

properties

将覆寫先前的

@TestPropertySource

locations

properties

此外,你可以在一個測試類上聲明多個組合注解,每個注解都用

@TestPropertySource

進行元注解,所有這些

@TestPropertySource

聲明都将貢獻給你的測試屬性源。直接呈現的

@TestPropertySource注解

總是優先于元呈現的

@TestPropertySource

注解。換句話說,直接存在的

@TestPropertySource

locations

properties

将覆寫

@TestPropertySource

注解中用作元注解的

locations

properties

預設屬性檔案檢測

@TestPropertySource

被聲明為空注解(即,沒有

locations

properties

的顯式值),則嘗試檢測相對于聲明該注解的類的預設屬性檔案。例如,如果帶注解的測試類是

com.example.MyTest

,則相應的對應屬性檔案是

classpath:com/example/MyTest.properties

。如果無法檢測到預設值,則抛出

IllegalStateException

優先順序

測試屬性的優先級高于在作業系統環境、Java系統屬性或應用程式通過使用

@PropertySource

聲明性地或以程式設計方式添加的屬性源中定義的屬性。是以,測試屬性可用于有選擇地覆寫從系統和應用程式屬性源加載的屬性。此外,内聯屬性優先于從資源位置加載的屬性。但是請注意,通過

@DynamicPropertySource

注冊的屬性比通過

@TestPropertySource

加載的屬性具有更高的優先級。

在下一個示例中,

timezone

port

屬性以及在

/test.properties

中定義的任何屬性都将覆寫在系統和應用程式屬性源中定義的同名屬性。此外,如果

/test.properties

檔案定義了

timezone

port

屬性的條目,則這些條目将被使用

properties

屬性聲明的内聯屬性所覆寫。

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

繼承和覆寫測試屬性源

@TestPropertySource

支援布爾型的

inheritLocations

inheritProperties

屬性,它們表示屬性檔案的資源位置和超類聲明的内聯屬性是否應該被繼承。這兩個标志的預設值為

true

。這意味着測試類将繼承任何超類聲明的位置和内聯屬性。具體來說,測試類的位置和内聯屬性附加到父類聲明的位置和内聯屬性。是以,子類可以選擇擴充位置和内聯屬性。注意,後面出現的屬性會隐藏(即覆寫)前面出現的同名屬性。此外,前面提到的優先規則也适用于繼承的測試屬性源。

@TestPropertySource

InheritLocations

InheritProperties

屬性設定為

false

,則分别為測試類設定位置或内聯屬性,并有效替換超類定義的配置。

BaseTest

ApplicationContext

是通過隻使用

base

加載的。屬性檔案作為測試屬性源。相反,

ExtendedTest

ApplicationContext

是通過使用

base

加載的屬性和擴充。屬性檔案作為測試屬性源位置。下面的示例示範如何使用屬性檔案在子類及其超類中定義屬性:

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

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

在下一個示例中,僅使用内聯的

key1

屬性來加載

BaseTest

ApplicationContext

。相反,使用内聯的

key1

key2

ExtendedTest

ApplicationContext

。下面的示例示範如何通過使用内聯屬性在子類及其父類中定義屬性:

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

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

從Spring架構5.2.5開始,

TestContext

架構通過

@DynamicPropertySource

注解提供對動态屬性的支援。此注解可用于需要向為內建測試加載的

ApplicationContext

的環境中的

PropertySources

集添加帶有動态值的屬性的內建測試。

@DynamicPropertySource

注解及其支援的基礎結構最初旨在使基于

Testcontainers

的測試中的屬性易于暴露于Spring內建測試。但是,此功能還可以用于其生命周期在測試的

ApplicationContext

之外維護的任何形式的外部資源。

與在類級别應用

@TestPropertySource

注解相反,

@DynamicPropertySource

必須應用于接受單個

DynamicPropertyRegistry

參數的靜态方法,該參數用于向環境添加

名稱/值

對。值是動态的,并通過

Supplier

提供,隻有在解析屬性時才調用

Supplier

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

Testcontainers

項目在Spring

ApplicationContext

之外管理一個Redis容器。通過

redis.host

redis.port

屬性,測試的

ApplicationContext

中的元件可以使用托管Redis容器的IP位址和端口。這些屬性可以通過Spring的環境抽象通路,或者直接注入到Spring管理的元件中,例如分别通過

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

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

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

    @Container
    static RedisContainer redis = new RedisContainer();

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

    // tests ...

}           

動态屬性的優先級高于

@TestPropertySource

、作業系統的環境、Java系統屬性或應用程式通過

@PropertySource

聲明性地或以程式設計方式添加的屬性源中加載的屬性。是以,動态屬性可用于有選擇地覆寫通過

@TestPropertySource

、系統屬性源和應用程式屬性源加載的屬性。

WebApplicationContext

若要訓示

TestContext

架構加載

WebApplicationContext

而不是标準

ApplicationContext

@WebAppConfiguration

注解各自的測試類。

測試類上

@WebAppConfiguration

的存在訓示

TestContext

架構(TCF)應該為內建測試加載

WebApplicationContext

(WAC)。TCF在背景確定建立了

MockServletContext

并将其提供給測試的WAC。預設情況下,你的

MockServletContext

的基本資源路徑設定為

src/main/webapp

。這被解釋為相對于JVM根目錄的路徑(通常是項目的路徑)。如果你熟悉Maven項目中Web應用程式的目錄結構,則知道

src/main/webapp

是WAR根目錄的預設位置。如果需要覆寫此預設值,則可以提供

@WebAppConfiguration

注解的替換路徑(例如,

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

。如果你希望從類路徑而不是檔案系統中引用基本資源路徑,則可以使用Spring的

classpath:

字首。

請注意,Spring對

WebApplicationContext

實作的測試支援與其對标準

ApplicationContext

實作的支援相當。使用

WebApplicationContext

進行測試時,可以使用

@ContextConfiguration

聲明XML配置檔案、Groovy腳本或

@Configuration

類。你還可以自由地使用任何其他測試注解,如

@ActiveProfiles

@Testexecutionlistener

@Sql

@Rollback

和其他。

本節的其餘示例展示了加載

WebApplicationContext

的一些不同配置選項。以下示例顯示了

TestContext

架構對配置約定的支援:

@ExtendWith(SpringExtension.class)

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

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

如果使用

@WebAppConfiguration

注解測試類而未指定資源基本路徑,則資源路徑實際上預設為

file:src/main/webapp

。同樣,如果在聲明

@ContextConfiguration

時未指定資源位置、元件類或上下文初始化程式,則Spring會嘗試使用約定(也就是說,

WacTests-context.xml

WacTests

類或靜态嵌套

@Configuration

類位于同一包中)。

以下示例顯示如何使用

@WebAppConfiguration

顯式聲明資源基本路徑和使用

@ContextConfiguration

顯式聲明XML資源位置:

@ExtendWith(SpringExtension.class)

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

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

這裡要注意的重要一點是具有這兩個注解的路徑的語義不同。預設情況下,

@ WebAppConfiguration

資源路徑基于檔案系統,而

@ContextConfiguration

資源位置基于類路徑。下面的示例顯示,我們可以通過指定Spring資源字首來覆寫兩個注解的預設資源語義:

@ExtendWith(SpringExtension.class)

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

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

将本示例中的注解與上一個示例進行對比。

使用Web Mock工作

為了提供全面的Web測試支援,

TestContext

架構具有預設啟用的

ServletTestExecutionListener

。在針對

WebApplicationContext

進行測試時,此

TestExecutionListener

會在每個測試方法之前使用Spring Web的

RequestContextHolder

來設定預設的線程本地狀态,并根據通過

@WebAppConfiguration

配置的基本資源路徑建立

MockHttpServletRequest

MockHttpServletResponse

ServletWebRequest

ServletTestExecutionListener

還確定可以将

MockHttpServletResponse

ServletWebRequest

注入到測試執行個體中,并且一旦測試完成,它将清除線程本地狀态。

一旦為測試加載了

WebApplicationContext

,你可能會發現你需要與Web模拟進行互動,例如,在調用Web元件之後設定測試

fixture

或執行斷言。以下示例顯示可以将哪些模拟自動裝配到你的測試執行個體。請注意,

WebApplicationContext

MockServletContext

都緩存在測試套件中,而其他模拟則由

ServletTestExecutionListener

針對每個測試方法進行管理。

@SpringJUnitWebConfig
class WacTests {

    @Autowired
    WebApplicationContext wac; // cached

    @Autowired
    MockServletContext servletContext; // cached

    @Autowired
    MockHttpSession session;

    @Autowired
    MockHttpServletRequest request;

    @Autowired
    MockHttpServletResponse response;

    @Autowired
    ServletWebRequest webRequest;

    //...
}           

一旦

TestContext

架構為測試加載了

ApplicationContext

(或

WebApplicationContext

),該上下文将被緩存并重新用于在同一測試套件中聲明相同唯一上下文配置的所有後續測試。要了解緩存的工作原理,重要的是要了解

unique

測試套件

的含義。

可以通過用于加載它的配置參數的組合來唯一辨別

ApplicationContext

。是以,使用配置參數的唯一組合來生成一個鍵,在該鍵下緩存上下文。

TestContext

架構使用以下配置參數來建構上下文緩存鍵:

  • locations

    (來自

    @ContextConfiguration

    )
  • classes

    @ContextConfiguration

  • contextInitializerClasses

    @ContextConfiguration

  • contextCustomizers

    ContextCustomizerFactory

    )其中包括

    @DynamicPropertySource

    方法,以及Spring Boot測試支援中的各種功能,例如

    @MockBean

    @SpyBean

  • contextLoader

    @ContextConfiguration

  • parent

    @ContextHierarchy

  • activeProfiles

    @ActiveProfiles

  • propertySourceLocations

    @TestPropertySource

  • propertySourceProperties

    @TestPropertySource

  • resourceBasePath

    @WebAppConfiguration

例如,如果

TestClassA

@ContextConfiguration

location

value

)屬性指定

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

,則

TestContext

架構将加載相應的

ApplicationContext

并将其存儲在靜态上下文緩存中僅基于那些位置的key下。是以,如果

TestClassB

還為其位置(通過繼承顯式或隐式)定義了

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

,但未定義

@WebAppConfiguration

、不同的

ContextLoader

、不同的激活配置檔案、不同的上下文初始化程式、不同的測試屬性源或不同的父上下文,則兩個測試類将共享相同的

ApplicationContext

。這意味着(每個測試套件)僅需加載一次加載應用程式上下文的設定成本,并且随後的測試執行要快得多。

測試套件和分支流程

Spring

TestContext

架構将應用程式上下文存儲在靜态緩存中。這意味着上下文實際上是存儲在靜态變量中的。換句話說,如果測試是在單獨的程序中執行的,則在每個測試執行之間都會清除靜态緩存,進而有效地禁用了緩存機制。

為了從緩存機制中受益,所有測試必須在同一程序或測試套件中運作。這可以通過在IDE中以組的形式執行所有測試來實作。同樣,在使用諸如Ant、Maven或Gradle之類的建構架構執行測試時,確定該建構架構不會在測試之間進行派生(fork多個程序)很重要。例如,如果将Maven Surefire插件的forkMode設定為always或pertest,則

TestContext

架構将無法在測試類之間緩存應用程式上下文,是以,建構過程的運作速度将大大降低。

上下文緩存的大小以預設的最大32為界。隻要達到最大大小,就會使用最近最少使用(LRU)驅逐政策來驅逐和關閉舊的上下文。你可以通過設定名為

spring.test.context.cache.maxSize

的JVM系統屬性,從指令行或建構腳本中配置最大大小。或者,你可以使用

SpringProperties

API以程式設計方式設定相同的屬性。

由于在給定的測試套件中加載大量的應用程式上下文會導緻該套件花費不必要的長時間來執行,是以準确地知道已加載和緩存了多少個上下文通常是有益的。要檢視基礎上下文緩存的統計資訊,可以将

org.springframework.test.context.cache

日志記錄類别的日志級别設定為

DEBUG

在不太可能的情況下,測試破壞了應用程式上下文并需要重新加載(例如,通過修改bean定義或應用程式對象的狀态),你可以使用

@DirtiesContext

注解測試類或測試方法(請參閱

@DirtiesContext

中對

@DirtiesContext

的讨論)。這訓示Spring在運作需要相同應用程式上下文的下一個測試之前,從緩存中删除上下文并重建應用程式上下文。請注意,預設情況下啟用的

DirtiesContextBeforeModesTestExecutionListener

DirtiesContextTestExecutionListener

提供了對

@DirtiesContext

注解的支援。

在編寫依賴于已加載的Spring

ApplicationContext

的內建測試時,通常足以針對單個上下文進行測試。但是,有時需要對

ApplicationContext

執行個體的層次結構進行測試是有益的,甚至是必要的。例如,如果你正在開發Spring MVC Web應用程式,則通常由Spring的

ContextLoaderListener

加載根

WebApplicationContext

,由Spring的

DispatcherServlet

加載子

WebApplicationContext

。這将導緻父子上下文層次結構,其中共享元件和基礎設施配置在根上下文中聲明,并由特定于web的元件在子上下文中使用。在Spring Batch應用程式中可以找到另一個用例,在該應用程式中,你通常具有一個父上下文,該上下文為共享批處理基礎結構提供配置,而子上下文則為特定批處理作業的配置提供配置。

你可以通過在單個測試類上或在測試類層次結構中使用

@ContextHierarchy

注解聲明上下文配置來編寫使用上下文層次結構的內建測試。如果在測試類層次結構中的多個類上聲明了上下文層次結構,則還可以合并或覆寫上下文層次結構中特定命名級别的上下文配置。合并層次結構中給定級别的配置時,配置資源類型(即XML配置檔案或元件類)必須一緻。否則,在使用不同資源類型配置的上下文層次結構中具有不同級别是完全可以接受的。

本節中其餘的基于JUnit Jupiter的示例顯示了需要使用上下文層次結構的內建測試的常見配置方案。

具有上下文層次結構的單個測試類

ControllerIntegrationTests

通過聲明一個上下文層次結構來代表Spring MVC Web應用程式的典型內建測試場景,該上下文層次結構包含兩個級别,一個層次用于根

WebApplicationContext

(通過使用

TestAppConfig

@Configuration類加載),一個層次用于排程程式Servlet

WebApplicationContext

WebConfig

@Configuration

類加載)。自動裝配到測試執行個體的

WebApplicationContext

是用于子上下文(即,層次結構中的最低上下文)的

WebApplicationContext

以下清單顯示了此配置方案:

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

    @Autowired
    WebApplicationContext wac;

    // ...
}           

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

具有隐式父上下文的類層次結構

本示例中的測試類在測試類層次結構中定義了上下文層次結構。

AbstractWebTests

在Spring驅動的Web應用程式中聲明根

WebApplicationContext

的配置。但是請注意,

AbstractWebTests

不會聲明

@ContextHierarchy

AbstractWebTests

的子類可以選擇參與上下文層次結構或遵循

@ContextConfiguration

的标準語義。

SoapWebServiceTests

RestWebServiceTests

都擴充了

AbstractWebTests

@ContextHierarchy

定義了上下文層次結構。結果是,加載了三個應用程式上下文(每個

@ContextConfiguration

聲明一個),并且基于

AbstractWebTests

中的配置加載的應用程式上下文被設定為具體子類加載的每個上下文的父上下文。

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

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

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

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

合并上下文層次結構配置的類層次結構

此示例中的類顯示了使用命名層次結構級别的目的,以及合并上下文層次結構中特定級别的配置。

BaseTests

在層次結構中定義了兩個級别,

parent

child

ExtendedTests

擴充

BaseTests

并訓示Spring

TestContext

架構合并子層次結構級别的上下文配置,方法是確定在

@ContextConfiguration

的name屬性中聲明的名稱均為子元素。結果是加載了三個應用程式上下文:一個用于

/app-config.xml

、一個用于

/user-config.xml

{/user-config.xml

/order-config.xml}

。與前面的示例一樣,将從

/app-config.xml

加載的應用程式上下文設定為從

/user-config.xml

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

加載的上下文的父上下文(合并配置檔案)。以下清單顯示了此配置方案:

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

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

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

具有覆寫的上下文層次結構配置的類層次結構

與前面的示例相反,此示例示範了如何通過将

@ContextConfiguration

InheritLocations

标志設定為

false

來覆寫上下文層次結構中給定命名級别的配置。是以,

ExtendedTests

的應用程式上下文僅從

/test-user-config.xml

加載,并且其父級設定為從

/app-config.xml

加載的上下文。以下清單顯示了此配置方案:

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

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

清除上下文層次結構中的上下文

如果你在一個測試中使用@DirtiesContext,該測試的上下文被配置為上下文層次結構的一部分,那麼你可以使用hierarchyMode标志來控制如何清除上下文緩存。有關更多詳細資訊,請參見

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

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

3.5.6 測試裝置的依賴注入

當使用

DependencyInjectionTestExecutionListener

(預設配置)時,測試執行個體的依賴項是從使用

@ContextConfiguration

或相關注解配置應用程式上下文中的bean注入的。你可以使用

setter

注入、字段注入、或同時使用這兩種方法,具體取決于你選擇的注解以及是否将它們放在

setter

方法或字段上。如果你使用的是JUnit Jupiter,則還可以選擇使用構造函數注入(請參閱帶有

SpringExtension的依賴注入

)。為了與Spring基于注解的注入支援保持一緻,你還可以将Spring的

@Autowired

注解或JSR-330中的

@Inject

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

對于JUnit Jupiter以外的測試架構,

TestContext

架構不參與測試類的執行個體化。是以,将

@Autowired

@Inject

用于構造函數對測試類無效。

盡管在生産代碼中不鼓勵使用字段注入,但是在測試代碼中字段注入實際上是很自然的。理由是你永遠不會直接執行個體化測試類。是以,不需要在測試類上調用公共構造函數或

setter

方法。

因為

@Autowired

用于按類型執行自動裝配,是以如果你具有多個相同類型的Bean定義,那麼對于那些特定的Bean,你将不能依靠這種方法。在這種情況下,可以将

@Autowired

@Qualifier

結合使用。你也可以選擇将

@Inject

@Named

結合使用。或者,如果你的測試類可以通路其

ApplicationContext

,則可以通過使用(例如)對

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

的調用來執行顯式查找。

如果你不希望将依賴項注入應用于測試執行個體,請不要使用

@Autowired

@Inject

注解字段或設定器方法。或者,你可以通過顯式地用

@TestExecutionListeners

配置你的類,并從監聽器清單中忽略

DependencyInjectionTestExecutionListener.class

來禁用依賴注入。

考慮測試

HibernateTitleRepository

類的場景,如

目标

部分所述。接下來的兩個代碼清單示範了

@Autowired

在字段和

setter

方法上的用法。在所有示例代碼清單之後顯示了應用程式上下文配置。

以下代碼清單中的依賴項注入行為并非特定于JUnit Jupiter。相同的

DI

技術可以與任何受支援的測試架構結合使用。

以下示例對靜态斷言方法(例如

assertNotNull()

)進行了調用,但沒有在聲明前添加

Assertions

。在這種情況下,假定該方法是通過示例中未顯示的

import static

聲明正确導入的。

第一個代碼清單顯示了使用

@Autowired

進行字段注入的測試類的基于JUnit Jupiter的實作:

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

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

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

或者,你可以将類配置為使用

@Autowired

進行

setter

注入,如下所示:

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

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

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

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

前面的代碼清單使用

@ContextConfiguration

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

repository-config.xml

)。下面顯示了此配置:

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

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

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

</beans>           
如果你是從Spring提供的測試基類擴充而來的,而該基類恰巧在其

setter

方法之一上使用

@Autowired

,則可能在應用程式上下文中定義了多個受影響類型的Bean(例如,多個

DataSource

Bean)。在這種情況下,你可以覆寫setter方法,并使用

@Qualifier

注解訓示特定的目标bean,如下所示(但請確定也委托給超類中的重寫方法):
// ...

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

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

DataSource

Bean,進而将類型比對的範圍縮小到特定Bean。其值與相應的定義中的聲明比對。Bean名稱用作後備限定符值,是以你也可以在該名稱中有效地指向特定的Bean(如先前所示,假設

myDataSource

是Bean

ID

作者

個人從事金融行業,就職過易極付、思建科技、某網約車平台等重慶一流技術團隊,目前就職于某銀行負責統一支付系統建設。自身對金融行業有強烈的愛好。同時也實踐大資料、資料存儲、自動化內建和部署、分布式微服務、響應式程式設計、人工智能等領域。同時也熱衷于技術分享創立公衆号和部落格站點對知識體系進行分享。關注公衆号:青年IT男 擷取最新技術文章推送!

部落格位址:

http://youngitman.tech

CSDN:

https://blog.csdn.net/liyong1028826685

微信公衆号:

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

技術交流群:

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