1. 概述
在開發和部署流程的不同階段,通常會創建不同的配置。實際上,當我們部署 Spring 應用時,可以為每個階段分配一個 Spring Profile,並創建專門的測試。
在本教程中,我們將重點介紹使用 JUnit 5 基於活動 Spring Profile 執行測試。
2. 項目設置
首先,讓我們將 <a href="https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web">spring-boot-starter-web`` 依賴添加到我們的項目中:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>現在讓我們創建一個簡單的 Spring Boot 應用程序:
@SpringBootApplication
public class ActiveProfileApplication {
public static void main (String [] args){
SpringApplication.run(Application.class);
}
}最後,讓我們創建一個 application.yaml 文件,用作我們的默認屬性源文件。
3. Spring 配置文件
Spring 配置文件提供了一種定義和管理不同環境的方法,通過將特定於每個環境的配置設置進行分組。
實際上,通過激活特定的配置文件,我們可以輕鬆地在不同的配置和設置之間切換。
3.1. 在屬性文件中啓用配置文件
我們可以通過在 application.yaml 文件中指定啓用配置文件:
spring:
profiles:
active: dev現在,Spring 將檢索活動配置文件的所有屬性,並將所有專用 Bean 加載到應用程序上下文中。
在本教程中,我們將為每個配置文件創建專用屬性文件。這是因為為每個特定環境管理和更新配置的過程,擁有每個配置文件的專用文件可以簡化該過程。
因此,讓我們為 test 和 prod 環境創建兩個配置文件,每個配置文件都包含 profile.property.value 屬性,但具有與文件名相對應的不同值。
因此,讓我們創建一個 application-prod.yaml 文件並添加 profile.property.value 屬性:
profile:
property:
value: This the the application-prod.yaml file同樣,我們對 application-test.yaml 也做相同的處理:
profile:
property:
value: This the the application-test.yaml file最後,讓我們將相同的屬性添加到 application.yaml 中:
profile:
property:
value: This the the application.yaml file現在,讓我們編寫一個簡單的測試,以驗證該應用程序在當前環境中是否按預期運行:
@SpringBootTest(classes = ActiveProfileApplication.class)
public class DevActiveProfileUnitTest {
@Value("${profile.property.value}")
private String propertyString;
@Test
void whenDevIsActive_thenValueShouldBeKeptFromApplicationYaml() {
Assertions.assertEquals("This the the application.yaml file", propertyString);
}
}變量 propertyString 中注入的值來源於 application.yaml 中定義的屬性值。這是因為 dev 是在測試執行期間激活的 profile,並且沒有為該 profile 定義任何屬性文件。
3.2. 在測試類中設置活動配置文件
通過設置 spring.profiles.active 屬性,我們可以激活相應的配置文件並加載與之相關的配置文件。
但是,在某些情況下,我們可能需要以特定配置文件的形式執行測試類,從而覆蓋 properties 文件中定義的活動配置文件。
因此,我們可以使用 @ActiveProfiles 標註,該標註與 JUnit 5 兼容,用於聲明在加載測試類應用程序上下文時使用的活動配置文件。
例如,如果我們在測試類上添加 @ActiveProfiles 標註,並將 value 屬性設置為 test,則該測試類中的所有測試將使用 test 配置文件:
@SpringBootTest(classes = ActiveProfileApplication.class)
@ActiveProfiles(value = "test")
public class TestActiveProfileUnitTest {
@Value("${profile.property.value}")
private String propertyString;
@Test
void whenTestIsActive_thenValueShouldBeKeptFromApplicationTestYaml() {
Assertions.assertEquals("This the the application-test.yaml file", propertyString);
}
}value 屬性,它是 profiles 屬性的別名,是一個字符串數組。 這是因為可以使用逗號分隔的列表指定多個活動配置文件。
例如,如果我們想指定活動配置文件為 test 和 prod,我們可以使用:
@ActiveProfiles({"prod", "test"})
這樣,應用程序上下文將使用 test 和 prod 配置文件特有的屬性和配置進行配置。
配置將在它們列出的順序上應用。 在不同配置文件的配置之間存在衝突的情況下,最後列出的配置將優先採用。
因此,基於活動配置運行測試對於確保應用程序在不同環境中行為正確至關重要。 但是,在其他環境中執行為特定配置文件設計的測試可能會帶來重大風險。 例如,在本地機器上運行測試時,我們可能會無意中運行為生產環境設計的測試。
為了避免這種情況,我們需要找到一種基於活動配置過濾測試執行的方法。
4. Annotation
在 JUnit 4 中,可以使用 註解來條件執行測試。實際上,它指定了測試必須滿足的條件。
但是,當我們的單元測試框架是 JUnit 5 時,我們應該避免使用 ,因為它在當前版本中已不再受支持。
因此,我們可以使用 ,一個允許啓用或禁用方法或類的註解。
JUnit 5 還提供了 註解。因此,我們應該確保我們正在導入 Spring 提供的版本,以避免混淆。
此註解具有以下屬性:
- value: 應該設置為 true 的條件表達式,以啓用測試類或單個測試
- expression: 它也指定了條件表達式。實際上,它標記為
- loadContext: 指定是否需要加載上下文以評估條件。默認值為 false
- reason: 解釋為什麼需要該條件
為了評估使用 Spring 應用上下文中定義的的值(如活動配置文件)的條件,我們應該將 loadContext 布爾屬性設置為 true。
4.1. 為單個配置文件運行測試
如果我們要僅在單個配置文件處於活動狀態時運行測試類,可以使用 SPEL 函數評估屬性 <em value</em>:
#{environment.getActiveProfiles()[0] == 'prod'}在該函數中,環境變量 是一個實現了 Environment 的對象。因此,environment.getActiveProfiles() 返回當前環境中的活動配置文件數組,而 [0] 則訪問該數組的第一個元素。
讓我們為我們的測試添加註釋:
@SpringBootTest(classes = ActiveProfileApplication.class)
@EnabledIf(value = "#{environment.getActiveProfiles()[0] == 'prod'}", loadContext = true)
public class ProdActiveProfileUnitTest {
@Value("${profile.property.value}")
private String propertyString;
@Test
void whenProdIsActive_thenValueShouldBeKeptFromApplicationProdYaml() {
Assertions.assertEquals("This the the application-prod.yaml file", propertyString);
}
}然後,讓我們通過使用 prod 配置文件來激活 @ActiveProfiles:
@SpringBootTest(classes = ActiveProfileApplication.class)
@EnabledIf(value = "#{environment.getActiveProfiles()[0] == 'prod'}", loadContext = true)
@ActiveProfiles(value = "prod")
public class ProdActiveProfileUnitTest {
@Value("${profile.property.value}")
private String propertyString;
@Test
void whenProdIsActive_thenValueShouldBeKeptFromApplicationProdYaml() {
Assertions.assertEquals("This the the application-prod.yaml file", propertyString);
}
}因此,我們課程中的測試始終會使用為 prod 配置文件指定的配置運行,並且噹噹前配置文件實際上為 prod 時。
4.2. 在多個配置文件下運行測試
如果想要在不同的活動配置文件下執行我們的測試,我們可以使用 SPEL 函數評估 <em value> 或 <em expression> 屬性:
#{{'test', 'prod'}.contains(environment.getActiveProfiles()[0])}讓我們分解一下這個函數:
{'test', 'prod'}定義了一組兩個 profile 名稱,這些名稱在我們的 Spring 應用中定義.contains{environment-getActiveProfiles()[0]}檢查該先前定義的集合中是否包含數組的第一個元素
因此,讓我們向我們的測試類添加 @EnableIf 標註:
@SpringBootTest(classes = ActiveProfileApplication.class)
@EnabledIf(value = "#{{'test', 'prod'}.contains(environment.getActiveProfiles()[0])}", loadContext = true)
@ActiveProfiles(value = "test")
public class MultipleActiveProfileUnitTest {
@Value("${profile.property.value}")
private String propertyString;
@Autowired
private Environment env;
@Test
void whenDevIsActive_thenValueShouldBeKeptFromDedicatedApplicationYaml() {
String currentProfile = env.getActiveProfiles()[0];
Assertions.assertEquals(String.format("This the the application-%s.yaml file", currentProfile), propertyString);
}
}因此,我們課程中的測試始終會在活動配置文件為 test 或 prod 時運行。
5. 結論
在本文中,我們學習瞭如何使用 JUnit 5 註解基於活動 Spring 配置文件執行測試。我們學習瞭如何在測試類中啓用配置文件,以及當一個或多個特定配置文件處於活動狀態時如何執行這些測試。