新聞中心
而不可否認(rèn)的是,隨著業(yè)界廣泛采用云端微服務(wù),我們?cè)诘靡嬗谔幚矶鄠€(gè)可獨(dú)立部署的組件的同時(shí),需要提高微服務(wù)應(yīng)用的測(cè)試級(jí)別,并按需增加測(cè)試策略的復(fù)雜性。下面,我將從使用者的角度出發(fā),以一個(gè)Spring Cloud微服務(wù)為例,深入探究各種服務(wù)組件的相關(guān)測(cè)試。

站在用戶(hù)的角度思考問(wèn)題,與客戶(hù)深入溝通,找到本溪網(wǎng)站設(shè)計(jì)與本溪網(wǎng)站推廣的解決方案,憑借多年的經(jīng)驗(yàn),讓設(shè)計(jì)與互聯(lián)網(wǎng)技術(shù)結(jié)合,創(chuàng)造個(gè)性化、用戶(hù)體驗(yàn)好的作品,建站類(lèi)型包括:成都網(wǎng)站設(shè)計(jì)、成都網(wǎng)站建設(shè)、企業(yè)官網(wǎng)、英文網(wǎng)站、手機(jī)端網(wǎng)站、網(wǎng)站推廣、空間域名、虛擬空間、企業(yè)郵箱。業(yè)務(wù)覆蓋本溪地區(qū)。
服務(wù)
我們的Spring Boot微服務(wù)示例會(huì)具有如下特征:
- 將啟用??Spring Cloud Netflix??。它會(huì)使用Spring Boot應(yīng)用的Netflix OSS集成,來(lái)執(zhí)行服務(wù)注冊(cè)與發(fā)現(xiàn)、分布式外部配置(Spring Cloud Config)、以及客戶(hù)端的負(fù)載平衡
- 將與關(guān)系型數(shù)據(jù)庫(kù)(如PostgreSQL)相集成
- 將能調(diào)用另一個(gè)(內(nèi)部)微服務(wù)
- 將調(diào)用第三方(外部)Web服務(wù)
- 將啟用Spring Security,以充當(dāng)OAuth2的資源服務(wù)器
- 將被“隱藏”在API網(wǎng)關(guān)服務(wù)器,例如??Spring Cloud Gateway??的后面
我們將通過(guò)Java 11、Apache Maven、Docker、以及一組協(xié)作庫(kù),“盡早地”在CI/CD管道中,進(jìn)行單獨(dú)的服務(wù)測(cè)試,而無(wú)需實(shí)際部署或占用其他服務(wù)、數(shù)據(jù)庫(kù)、甚至是完整的測(cè)試環(huán)境資源。同時(shí),您可以通過(guò)鏈接--https://github.com/kmandalas/spring-cloud-component-tests,在GitHub上獲取該示例的所有代碼。
該示例中的“訂單跟蹤”微服務(wù)是由一個(gè)Spring Controller、Service和Repository所組成。它公開(kāi)了兩個(gè)端點(diǎn):
- GET/api/orders/{trackingNumber}/status:它通過(guò)給定的跟蹤號(hào),執(zhí)行數(shù)據(jù)庫(kù)查詢(xún),來(lái)獲取相關(guān)訂單;然后調(diào)用FulfillmentService的內(nèi)部服務(wù),來(lái)確定交付的狀態(tài);進(jìn)而讓最終外部服務(wù)根據(jù)狀態(tài),調(diào)用位置服務(wù)來(lái)實(shí)現(xiàn)定位。這是一個(gè)帶有有效的JWT、且受保護(hù)的API調(diào)用。
- GET/api/orders:通過(guò)查詢(xún)數(shù)據(jù)庫(kù),以列出所有訂單。這是一個(gè)受到額外授權(quán)限制的、且受保護(hù)的API調(diào)用。它僅適用于具有“back-office”角色的用戶(hù)。
組件測(cè)試
OrderControllerTest.java類(lèi)將針對(duì)API提供的多種方法,來(lái)封裝組件測(cè)試。例如,我們可以選用包括:??Maven插件??、??JUnit功能??、??Spring Boot測(cè)試切片??和分類(lèi)單元測(cè)試、集成測(cè)試、組件測(cè)試、合同測(cè)試等方法。當(dāng)然,并非所有的測(cè)試類(lèi)別都需要在CI/CD管道中被執(zhí)行(或重新執(zhí)行)。鑒于該示例過(guò)于簡(jiǎn)單,我強(qiáng)烈建議您實(shí)施適當(dāng)?shù)姆诸?lèi)。
在??/src/test/resources/application.yml??中,我們針對(duì)屬性的測(cè)試配置如下:
YAML
server:
port: 0
spring:
application:
name: order-service-test
cloud:
service-registry:
auto-registration:
enabled: false
loadbalancer:
ribbon:
enabled: false
config:
enabled: false
jpa:
show-sql: true
eureka:
client:
enabled: false
service-url:
registerWithEureka: false
okta:
oauth2:
issuer: https://kmandalas/oauth2/default
location-service:
url: http://localhost:9999/v1/track/
在上述代碼段所示中,我們禁用spring.cloud.config、eureka.client和spring.cloud.service-registry.auto-registration的原因在于,方便孤立地測(cè)試微服務(wù)。因此,既不會(huì)有Spring Cloud Config服務(wù)器在啟動(dòng)時(shí),為OrderService的配置屬性提供服務(wù);也不會(huì)有Eureka服務(wù)器提供注冊(cè),并能夠使用它來(lái)按需調(diào)用FulfillmentService的動(dòng)態(tài)服務(wù)發(fā)現(xiàn)。
數(shù)據(jù)庫(kù)
當(dāng)出于測(cè)試目的而必須與數(shù)據(jù)庫(kù)(關(guān)系型或NoSQL)集成時(shí),我們通常有如下三種選擇:
- 使用嵌入式或內(nèi)存中(in-memory)方案,例如:H2,https://www.h2database.com/
- 使用一個(gè)能在測(cè)試期間可供訪(fǎng)問(wèn)的真實(shí)數(shù)據(jù)庫(kù)
- 使用與生產(chǎn)數(shù)據(jù)庫(kù)接近甚至相同的臨時(shí)數(shù)據(jù)庫(kù)
不同的選項(xiàng)所涉及到的測(cè)試資源,將會(huì)不盡相同。
- 如果采用第一種方法,將H2進(jìn)行集成和組件測(cè)試,那么由于生產(chǎn)環(huán)境的數(shù)據(jù)庫(kù)很可能與H2不同,因此您將不得不維護(hù)各種獨(dú)立的DDL和DML腳本。此外,您也可能會(huì)用到原生查詢(xún)、或其他特定于某個(gè)數(shù)據(jù)庫(kù)的功能。
- 如果您需要進(jìn)行端到端或性能測(cè)試的話(huà),那么就應(yīng)該部署真實(shí)的數(shù)據(jù)庫(kù),并在測(cè)試環(huán)境中啟動(dòng)并運(yùn)行它。對(duì)此,現(xiàn)代化的IaC(infrastructure as code,基礎(chǔ)設(shè)施即代碼)工具、以及詳盡的??測(cè)試數(shù)據(jù)管理??,將可以為項(xiàng)目按需提供靈活性。
- 在本測(cè)試示例中,我們將使用第三種方法,利用??testcontainers???和??Flyway??,實(shí)現(xiàn)與Spring Boot的配合,而數(shù)據(jù)庫(kù)才采用PostgreSQL。在testcontainers的幫助下,我們將在測(cè)試的初始化階段,創(chuàng)建一個(gè)臨時(shí)的dockerized數(shù)據(jù)庫(kù)實(shí)例。而Flyway將會(huì)在這個(gè)臨時(shí)模式(schema)上觸發(fā)???遷移腳本??(DDL/DML),以便我們的代碼將透明地、針對(duì)該臨時(shí)模式運(yùn)行。而在測(cè)試完成時(shí),我們會(huì)處理掉這個(gè)dockerized數(shù)據(jù)庫(kù)。
可見(jiàn),我們實(shí)際上只需要OrderControllerTest類(lèi)上的@Testcontainers注釋?zhuān)约叭缦碌撵o態(tài)聲明:
Java
@Container
static PostgreSQLContainer database = new PostgreSQLContainer("postgres:12")
.withDatabaseName("tutorial")
.withUsername("kmandalas")
.withPassword("dzone2022");
?
@DynamicPropertySource
static void setDatasourceProperties(DynamicPropertyRegistry propertyRegistry) {
propertyRegistry.add("spring.datasource.url", database::getJdbcUrl);
propertyRegistry.add("spring.datasource.password", database::getPassword);
propertyRegistry.add("spring.datasource.username", database::getUsername);
}
內(nèi)部服務(wù)調(diào)用
我們將使用??Spring Cloud OpenFeign??來(lái)調(diào)用FulfillmentService,它是另一個(gè)“內(nèi)部”的Spring Cloud微服務(wù),可以被注冊(cè)到Eureka上。在正常執(zhí)行的情況下,后臺(tái)的feign客戶(hù)端能夠通過(guò)名稱(chēng)定位目標(biāo)服務(wù)實(shí)例,實(shí)現(xiàn)客戶(hù)端的負(fù)載均衡(如果發(fā)現(xiàn)了多個(gè)實(shí)例的話(huà))。
在我們的測(cè)試中,在沒(méi)有Eureka(或者是??Consul??等其他發(fā)現(xiàn)機(jī)制)的情況下,我們需要通過(guò)如下兩個(gè)方面,盡可能真實(shí)地模擬此類(lèi)集成:
- 通過(guò)??WireMock??啟動(dòng)一個(gè)模擬服務(wù)器。該服務(wù)器能夠根據(jù)URL的不同模式,來(lái)截獲請(qǐng)求,并回復(fù)由我們提供的模擬響應(yīng)。
- 使用@TestConfiguration來(lái)模擬各種FulfillmentService實(shí)例的發(fā)現(xiàn),并將其指向WireMock服務(wù)器的URI。您可以通過(guò)鏈接--https://github.com/kmandalas/spring-cloud-component-tests/blob/50241126932fce3e9cfc6351291af5857f77806a/src/test/java/gr/kmandalas/dzone/OrderControllerTest.java#L55,查看到此類(lèi)測(cè)試配置。
當(dāng)然,您也可以使用??Hoverfly??作為嵌入式模擬服務(wù)器。在本示例里,我們通過(guò)如下依賴(lài)項(xiàng)設(shè)置,來(lái)引入WireMock:
XML
org.springframework.cloud
spring-cloud-starter-contract-stub-runner
test
通過(guò)spring-cloud-starter-contract-stub-runner,WireMock在Spring Boot應(yīng)用測(cè)試套件中的引導(dǎo)被簡(jiǎn)化了許多,同時(shí)這對(duì)于??契約測(cè)試??(contract tests)也是非常實(shí)用的。請(qǐng)通過(guò)查看Spring Cloud Contract WireMock的鏈接--https://docs.spring.io/spring-cloud-contract/docs/current/reference/html/project-features.html#features-wiremock,了解更多相關(guān)信息。
有了上面的基礎(chǔ),我們只需要使用@AutoConfigureWireMock去注釋測(cè)試類(lèi),并在測(cè)試資源目錄下的??JSON文件??中定義各種WireMock映射即可。
外部服務(wù)調(diào)用
在集成的過(guò)程中,為了能夠調(diào)用某些外部的(第三方)服務(wù),我們?nèi)匀恍枰蕾?lài)有效的WireMock映射(畢竟能夠提供的響應(yīng)多多益善),以便在??application.yml??中定義測(cè)試URL資源。下面是一個(gè)簡(jiǎn)單的示例:
YAML
location-service:
url: http://localhost:9999/v1/track/
我們?cè)谕獠糠?wù)的URL端點(diǎn)路徑處,提供了WireMock嵌入式服務(wù)器運(yùn)行的主機(jī)和端口。端口號(hào)雖然不必經(jīng)過(guò)硬編碼,但是可以被定義為動(dòng)態(tài)的,以便在CI/CD管道中并行運(yùn)行多個(gè)組件測(cè)試,且不會(huì)發(fā)生端口沖突。
值得一提的是,WireMock不僅可以用于模擬來(lái)自RESTful服務(wù)的各種JSON響應(yīng),還可以模擬基于SOAP的Web服務(wù)的響應(yīng)。
安全
正如前文提到的,Spring Cloud微服務(wù)基礎(chǔ)設(shè)施通常能夠合并出一個(gè)諸如Spring Cloud Gateway的API網(wǎng)關(guān)。據(jù)此,我們可以使用OAuth 2.0、JavaScript對(duì)象簽名和加密(Object Signing and Encryption,JOSE)、以及JSON Web令牌標(biāo)準(zhǔn)的令牌中繼模式,來(lái)處理用戶(hù)的身份識(shí)別,授權(quán)應(yīng)用程序查看他們的個(gè)人資料,以及訪(fǎng)問(wèn)網(wǎng)關(guān)后面的安全資源。通常,此類(lèi)安全設(shè)置會(huì)由如下組件構(gòu)成:
- 單點(diǎn)登錄服務(wù)器,如??Keycloak???、Cloud Foundry 的用戶(hù)帳戶(hù)和???身份驗(yàn)證服務(wù)器???、以及??諸如Okta??之類(lèi)商用的OAuth2身份驗(yàn)證提供程序。
- Spring Cloud Gateway之類(lèi)的API網(wǎng)關(guān)服務(wù)器,將用戶(hù)帳戶(hù)的管理和授權(quán)委托給單點(diǎn)登錄服務(wù)器。
- 資源服務(wù)器:在本Spring Boot微服務(wù)示例中為OrderService。
針對(duì)本測(cè)試示例,我們?cè)趩为?dú)測(cè)試Spring Boot微服務(wù)時(shí),會(huì)采用??Spring Security??的SecurityMockMvcRequestPostProcessors。它將使我們能夠在MockMvc調(diào)用期間,傳遞有效的JWT,定義權(quán)限(即用戶(hù)角色),并在啟用安全性的情況下,測(cè)試組件的行為。例如:
Java
mockMvc.perform(get("/api/orders/11212/status").with(jwt())).andExpect(status().isOk())和
mockMvc.perform(get("/api/orders/").with(jwt().authorities(new
SimpleGrantedAuthority("backoffice"))))
.andExpect(status().isOk());
小結(jié)
如今,對(duì)于成功的產(chǎn)品交付而言,開(kāi)發(fā)人員是否能夠在CI/CD管道中,以自動(dòng)化的方式執(zhí)行各類(lèi)測(cè)試是至關(guān)重要的。希望上述討論的有關(guān)Spring Cloud微服務(wù)組件測(cè)試的相關(guān)指南和注意事項(xiàng),能夠給您的實(shí)際項(xiàng)目交付提供幫助。
譯者介紹
陳峻 (Julian Chen),社區(qū)編輯,具有十多年的IT項(xiàng)目實(shí)施經(jīng)驗(yàn),善于對(duì)內(nèi)外部資源與風(fēng)險(xiǎn)實(shí)施管控,專(zhuān)注傳播網(wǎng)絡(luò)與信息安全知識(shí)與經(jīng)驗(yàn);持續(xù)以博文、專(zhuān)題和譯文等形式,分享前沿技術(shù)與新知;經(jīng)常以線(xiàn)上、線(xiàn)下等方式,開(kāi)展信息安全類(lèi)培訓(xùn)與授課。
原文標(biāo)題:Component Tests for Spring Cloud Microservices,作者:Kyriakos Mandalas和Dimitris Stavroulakis
網(wǎng)頁(yè)名稱(chēng):詳解Spring云端微服務(wù)的組件測(cè)試
瀏覽地址:http://m.fisionsoft.com.cn/article/djcdcdc.html


咨詢(xún)
建站咨詢(xún)
