想在不建立完整測試環(huán)境的情況下測試微服務(wù)?
想在將變更推送到主線分支之前完成測試?
這是我們在進(jìn)行項(xiàng)目交付時經(jīng)常遇到的難題。最近,當(dāng)我們開始一個新的項(xiàng)目,為客戶構(gòu)建一個新的聚合平臺時,我們希望將盡可能多的測試和自動化轉(zhuǎn)移到流程的合并前執(zhí)行。
我們知道,我們需要一種方法來對我們的服務(wù)執(zhí)行深度功能測試,并使我們的團(tuán)隊(duì)能夠獨(dú)立運(yùn)行。這就是促使我們開發(fā)用于微服務(wù)隔離和測試的測試腳手架(Test Scaffolding)的原因。
挑戰(zhàn)
在部署到集成環(huán)境之前,我們需要獨(dú)立于其他服務(wù)對微服務(wù)的變更進(jìn)行測試。這樣,當(dāng)我們將變更部署到上層環(huán)境時,就可以專注于測試集成和事務(wù)流,而不是單個服務(wù)的功能行為。
雖然我們可以將測試中的服務(wù)指向其依賴的測試環(huán)境,但這可能會導(dǎo)致兩個問題。
-
首先,環(huán)境用戶之間的數(shù)據(jù)混合會導(dǎo)致意想不到的行為。
-
其次,由于服務(wù)之間的連鎖調(diào)用,可能會出現(xiàn)延遲問題和測試緩慢。我們很快意識到,我們需要在合并前隔離服務(wù)的能力,以實(shí)現(xiàn)集中和完全隔離的功能測試自動化。
方法
我們決定通過引入一個名為測試腳手架Test Scaffolding的概念來隔離服務(wù)。
測試腳手架的工作是模擬微服務(wù)可能需要與之交互的所有外部服務(wù)。測試腳手架的作用與建筑腳手架的作用類似,隨著微服務(wù)交互的增加,會將其添加到腳手架中。每個服務(wù)都有自己的腳手架,與服務(wù)預(yù)合并(the service pre-merge)一起構(gòu)建和部署。
這樣就為我們的微服務(wù)提供了它所期望的依賴關(guān)系,并通過測試對輸入和輸出進(jìn)行細(xì)粒度控制。
這種方法對于獨(dú)立構(gòu)建服務(wù)并向我們的工程團(tuán)隊(duì)提供持續(xù)的早期反饋也至關(guān)重要。
微服務(wù)基礎(chǔ)知識
我們將在下面的示例中使用 AWS 術(shù)語,但這些概念應(yīng)適用于所有平臺。
開始之前,我們必須對如何定義與測試腳手架交互的功能測試范圍有一個共同的理解:
-
測試僅限于特定微服務(wù)的邊界。
-
測試已部署服務(wù)的交互屬于我們的行程測試(journey tests)。
-
在項(xiàng)目中,我們將微服務(wù)的邊界定義為服務(wù)CloudFormation Template(CFT)所定義的組件。
微服務(wù)中最常見的組件通常是API Gateway、Lambdas、Dynamo 和 SNS 或 SQS 的組合,我們可以用這樣的圖來表示:
在這個例子中,假設(shè)我們需要測試微服務(wù)A,微服務(wù)A在給定的數(shù)據(jù)流中與微服務(wù)B和C通信。由于這些服務(wù)的目的非常集中,因此它們必須聯(lián)系其他服務(wù)來驗(yàn)證外部信息。
微服務(wù)A與微服務(wù)B 、C對話
我們不想讓B和C的實(shí)例來測試A,所以我們需要隔離一些交互:
挑戰(zhàn):將A與B和C隔離
這正是測試腳手架的作用。它取代了服務(wù)B和C的位置,在測試中提供了大量關(guān)于如何設(shè)置和管理輸入和輸出的控制。
?
?
有幾點(diǎn)需要注意:
-
每個服務(wù)只有一個測試腳手架。我們可以根據(jù)需要在單個測試腳手架中添加多種不同類型的交互--即使它們代表不同服務(wù)的不同端點(diǎn)。
-
微服務(wù)和測試腳手架都由各自的 CloudFormation 模板(CFT)定義,但存儲在同一個項(xiàng)目 repo 中。
使用案例示例:
既然我們已經(jīng)定義了微服務(wù)的邊界,那就來討論幾個用例吧。
在第一個示例中,服務(wù)接受 API 請求,處理請求,然后通過 SNS 主題發(fā)送輸出。我們在項(xiàng)目中使用這種模式將信息發(fā)送到不同的聚合器服務(wù),這些聚合器服務(wù)會將數(shù)據(jù)映射成正確的格式,然后發(fā)布到多個第三方服務(wù)。
我們要確保輸入值得到正確處理,并輸出到 SNS 主題。與 SNS 交互非常棘手,因?yàn)樗枰嗛啿拍懿东@響應(yīng)。這很難在自動測試中即時完成,因此我們添加了一個 Lambda 來處理對 SNS 主題的訂閱,并添加了 DynamoDB 來保留響應(yīng),以便對測試腳手架進(jìn)行驗(yàn)證。
?
這樣,測試就可以向服務(wù)發(fā)送請求,讓服務(wù)處理請求,然后從腳手架 DynamoDB 中提取發(fā)送到 SNS 主題的結(jié)果,以確定結(jié)果是否符合我們的預(yù)期。
第二個示例與第一個示例類似。在這里,我們的微服務(wù)從 SNS 主題獲取事件,并調(diào)用服務(wù)進(jìn)行額外的狀態(tài)驗(yàn)證,例如產(chǎn)品是否處于活動狀態(tài)。然后,該狀態(tài)將發(fā)布到映射的外部服務(wù)。
在這種情況下,我們的測試腳手架將包含 SNS 主題、API 網(wǎng)關(guān)、Lambda 和 Dynamo。測試會將我們希望服務(wù)從測試腳手架 API 調(diào)用中接收的數(shù)據(jù)填充到 Dynamo 中,并觸發(fā) SNS 主題流以啟動測試。在處理過程中,微服務(wù)會將其狀態(tài)調(diào)用發(fā)送到測試腳手架中的 API 網(wǎng)關(guān),并獲取測試在此暫存的響應(yīng)。我們在微服務(wù)的 DynamoDB 中驗(yàn)證流程的最終輸出。
如示例所示,使用測試腳手架可以讓我們高度靈活地匹配服務(wù)的交互要求,從而可以完全隔離地測試每個服務(wù)。
腳手架設(shè)置、部署和執(zhí)行
那么,我們是如何配置這些服務(wù)從而確保它們在正確的區(qū)域內(nèi)運(yùn)行的呢?
為了取得成功,我們在云組建模板中進(jìn)行了參數(shù)化。測試腳手架和被測微服務(wù)都有各自的 CFT 來管理必要的資源。在微服務(wù) CFT 中,我們利用模板參數(shù)化和條件語句來控制測試腳手架的使用,具體取決于服務(wù)的部署方式。這些參數(shù)通過 CI/CD 管道傳入。在我們的預(yù)合并部署中,這可以讓微服務(wù)尋找測試腳手架,而在集成環(huán)境中,我們可以讓該服務(wù)尋找適當(dāng)?shù)囊巡渴鸱?wù)。
下面是根據(jù)輸入?yún)?shù)有條件使用測試腳手架的微服務(wù) CFT 片段:
Conditions:
condIsProd: !Equals [ !Ref paramEnvironment, prod ]
condNotFeatureBranch: !Equals [!Ref paramFeatureBranch, ""]
condIsLocal: !Equals [ !Ref paramEnvironment, local ]
condIsLocalOrBranch: !Or [ !Not [ Condition: condNotFeatureBranch ], Condition: condIsLocal ]
Resources:
resLambdaConvertPicture:
Type: AWS::Serverless::Function
Properties:
Handler: ConvertPicture.handler
FunctionName: !Sub "${paramEnvironment}${paramFeatureBranch}_${paramServiceName}_ConvertPicture"
CodeUri: dist/ConvertPicture.js
Policies:
- SNSPublishMessagePolicy:
TopicName: !If
- condIsLocalOrBranch
- !Sub "${paramEnvironment}${paramFeatureBranch}_${paramServiceName}-ts_catalog_pictureUploaded"
- !Sub "${paramEnvironment}${paramFeatureBranch}_catalog_PictureUploaded"
- DynamoDBCrudPolicy:
TableName: !Ref resDynamoMenuJobsTable
測試腳手架作為分支部署的一部分與微服務(wù)同時部署。下圖顯示了腳手架代碼必須遵守與其他服務(wù)相同的部署標(biāo)準(zhǔn)。部署完成后,我們將運(yùn)行功能測試。
帶有測試腳手架的分支部署CI/CD管道圖。
只有當(dāng)使用腳手架的隔離服務(wù)測試通過后,才有可能并入主線分支。測試腳手架不會部署到我們的集成環(huán)境中。一旦主線中出現(xiàn)變更,我們就會使用計劃作業(yè)來清理任何可能尚未手動拆除的隔離環(huán)境(服務(wù)和腳手架)。這一點(diǎn)很重要,因?yàn)榻o定賬戶的可用資源數(shù)量是有上限的。
測試,更上一層樓
測試腳手架允許我們的團(tuán)隊(duì)在合并到主線分支并部署到集成環(huán)境之前,使用與服務(wù)開發(fā)完全相同的技術(shù)(CFT 和本地 AWS 資源)獨(dú)立開發(fā)和測試微服務(wù)功能。通過腳手架控制輸入和輸出,我們可以圍繞關(guān)鍵流程建立更深入的測試集,并有效地確保高質(zhì)量。
由于測試腳手架允許我們創(chuàng)建的不僅僅是基本的創(chuàng)建、讀取更新和刪除測試,我們還能構(gòu)建與業(yè)務(wù)用例相關(guān)聯(lián)的深度功能流。這些深入的功能測試讓我們對微服務(wù)在合并到主線并部署到環(huán)境中之前的變化充滿信心。此外,將大部分自動化保持在這一級別(以及單元測試)可最大限度地減少行程測試(journey test)(即:"端到端測試")的使用,并支持測試金字塔所有級別的健康自動化套件。
一些亮點(diǎn):
-
每次推送到版本庫時都會執(zhí)行測試。
-
測試速度快!針對我們的一項(xiàng)主要服務(wù)進(jìn)行的幾百個測試中,運(yùn)行時間最長的一組測試不到10分鐘。
-
測試對即將進(jìn)行的合并進(jìn)行把關(guān)。如果測試不通過,你的提交就無法合并,也不會影響其他團(tuán)隊(duì)在其他服務(wù)上的工作。
-
測試定義并控制自己的所有數(shù)據(jù),使其具有完全的確定性和密封性。
經(jīng)驗(yàn)教訓(xùn)
在我們學(xué)習(xí)實(shí)施和利用測試腳手架的最佳方法時,需要不斷地嘗試和犯錯。我們既要確定如何將其納入項(xiàng)目,又要確定將其作為管道的一部分進(jìn)行構(gòu)建和部署的最佳方式。以下是一些關(guān)鍵經(jīng)驗(yàn):
KISS-("Keep It Simple, Stupid")我們傾向于將測試腳手架中的行為復(fù)雜化,從而不需要重復(fù)依賴邏輯來生成適當(dāng)?shù)捻憫?yīng)。
清理- 當(dāng)變更提交到主線時,服務(wù)和測試腳手架的測試版本就會被遺留下來。因此,我們建立了清理工作,以便從AWS開發(fā)賬戶中刪除不再處于活動開發(fā)階段或已數(shù)天未更新的工件。事實(shí)上,一切都由云形成堆棧定義,這使得根據(jù)需要重新部署變更變得非常容易。
契約演進(jìn)(Contract evolution)?- 測試腳手架中使用的請求和響應(yīng)與實(shí)際服務(wù)契約保持一致至關(guān)重要。否則,就無法測試應(yīng)該測試的內(nèi)容。團(tuán)隊(duì)間的溝通和合同測試仍然至關(guān)重要。文章來源:http://www.zghlxwxcb.cn/news/detail-685500.html
與任何新流程一樣,測試腳手架的開發(fā)和部署也需要時間和精力,但它最終成為了我們整體微服務(wù)開發(fā)方法中的一個強(qiáng)大工具和重要資產(chǎn)。文章來源地址http://www.zghlxwxcb.cn/news/detail-685500.html
到了這里,關(guān)于?無需測試環(huán)境!如何利用測試腳手架隔離微服務(wù),實(shí)現(xiàn)功能自動化的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!