微服務(wù)模式下API測(cè)試要怎么做?

文章內(nèi)容來(lái)源于《軟件測(cè)試52講》

微服務(wù)架構(gòu)下污桦,API 測(cè)試的最大挑戰(zhàn)來(lái)自于龐大的測(cè)試用例數(shù)量亩歹,以及微服務(wù)之間的相互耦合。



題外話
為了掌握微服務(wù)模式下的 API 測(cè)試凡橱,需要先了解微服務(wù)架構(gòu)(Microservice Architecture)的特點(diǎn)小作、測(cè)試挑戰(zhàn);而要了解微服務(wù)架構(gòu)稼钩,又需要先了解一些單體架構(gòu)(Monolithic Architecture)的知識(shí)顾稀。



單體架構(gòu)(Monolithic Architecture)

單體架構(gòu)是將所有的業(yè)務(wù)場(chǎng)景的表示層、業(yè)務(wù)邏輯層和數(shù)據(jù)訪問(wèn)層放在同一個(gè)工程中坝撑,最終經(jīng)過(guò)編譯静秆、打包,并部署在服務(wù)器上巡李。

比如抚笔,經(jīng)典的 J2EE 工程,它就是將表示層的 JSP侨拦、業(yè)務(wù)邏輯層的 Service殊橙、Controller 和數(shù)據(jù)訪問(wèn)層的 DAO(Data Access Objects),打包成 war 文件狱从,然后部署在 Tomcat膨蛮、Jetty 或者其他 Servlet 容器中運(yùn)行。

優(yōu)點(diǎn):發(fā)布簡(jiǎn)單季研、方便調(diào)試敞葛、架構(gòu)復(fù)雜性低
缺點(diǎn):
1、靈活性差
無(wú)論是多小的修改训貌,哪怕只修改了一行代碼制肮,也要打包發(fā)布整個(gè)應(yīng)用冒窍。更糟糕的是,由于所有模塊代碼都在一起豺鼻,所以每次編譯打包都要花費(fèi)很長(zhǎng)時(shí)間综液。
2、可擴(kuò)展性差
在高并發(fā)場(chǎng)景下儒飒,無(wú)法以模塊為單位靈活擴(kuò)展容量谬莹,不利于應(yīng)用的橫向擴(kuò)展。
3桩了、穩(wěn)定性差
當(dāng)單體應(yīng)用中任何一個(gè)模塊有問(wèn)題時(shí)附帽,都可能會(huì)造成應(yīng)用整體的不可用,缺乏容錯(cuò)機(jī)制井誉。
4蕉扮、可維護(hù)性差
隨著業(yè)務(wù)復(fù)雜性的提升,代碼的復(fù)雜性也是直線上升颗圣,當(dāng)業(yè)務(wù)規(guī)模比較龐大時(shí)喳钟,整體項(xiàng)目的可維護(hù)性會(huì)大打折扣。

微服務(wù)架構(gòu)(Microservice Architecture)

微服務(wù)是一種架構(gòu)風(fēng)格在岂。在微服務(wù)架構(gòu)下奔则,一個(gè)大型復(fù)雜軟件系統(tǒng)不再由一個(gè)單體組成,而是由一系列相互獨(dú)立的微服務(wù)組成蔽午。
其中易茬,各個(gè)微服務(wù)運(yùn)行在自己的進(jìn)程中,開(kāi)發(fā)和部署都沒(méi)有依賴及老。

不同服務(wù)之間通過(guò)一些輕量級(jí)交互機(jī)制進(jìn)行通信抽莱,例如 RPC、HTTP 等写半,服務(wù)可獨(dú)立擴(kuò)展伸縮岸蜗,每個(gè)服務(wù)定義了明確的邊界,只需要關(guān)注并很好地完成一件任務(wù)就可以了叠蝇,不同的服務(wù)可以根據(jù)業(yè)務(wù)需求實(shí)現(xiàn)的便利性而采用不同的編程語(yǔ)言來(lái)實(shí)現(xiàn)璃岳,由獨(dú)立的團(tuán)隊(duì)來(lái)維護(hù)。

單體架構(gòu) VS 微服務(wù)架構(gòu).png

特點(diǎn):
1悔捶、每個(gè)服務(wù)運(yùn)行在其獨(dú)立的進(jìn)程中铃慷,開(kāi)發(fā)采用的技術(shù)棧也是獨(dú)立的;
2蜕该、服務(wù)間采用輕量級(jí)通信機(jī)制進(jìn)行溝通犁柜,通常是基于 HTTP 協(xié)議的 RESTful API;
3堂淡、每個(gè)服務(wù)都圍繞著具體的業(yè)務(wù)進(jìn)行構(gòu)建馋缅,并且能夠被獨(dú)立開(kāi)發(fā)扒腕、獨(dú)立部署、獨(dú)立發(fā)布萤悴;
4瘾腰、對(duì)運(yùn)維提出了非常高的要求,促進(jìn)了 CI/CD 的發(fā)展與落地覆履。

微服務(wù)架構(gòu)下的測(cè)試挑戰(zhàn)
由于微服務(wù)架構(gòu)下蹋盆,一個(gè)應(yīng)用是由很多相互獨(dú)立的微服務(wù)組成,每個(gè)微服務(wù)都會(huì)對(duì)外暴露接口硝全,同時(shí)這些微服務(wù)之間存在級(jí)聯(lián)調(diào)用關(guān)系栖雾,也就是說(shuō)一個(gè)微服務(wù)通常還會(huì)去調(diào)用其他微服務(wù)。

鑒于以上特點(diǎn)伟众,微服務(wù)架構(gòu)下的測(cè)試挑戰(zhàn)主要來(lái)自于以下兩個(gè)方面:
1析藕、過(guò)于龐大的測(cè)試用例數(shù)量
在傳統(tǒng)的 API 測(cè)試中,我們的測(cè)試策略通常是:

  • 根據(jù)被測(cè) API 輸入?yún)?shù)的各種組合調(diào)用 API凳厢,并驗(yàn)證相關(guān)結(jié)果的正確性噪径;
  • 衡量上述測(cè)試過(guò)程的代碼覆蓋率;
  • 根據(jù)代碼覆蓋率進(jìn)一步找出遺漏的測(cè)試用例数初;
  • 以代碼覆蓋率達(dá)標(biāo)作為 API 測(cè)試成功完成的標(biāo)志。

假設(shè)我們采用單體架構(gòu)開(kāi)發(fā)了一個(gè)系統(tǒng)梗顺,這個(gè)系統(tǒng)對(duì)外提供了 3 個(gè) Restful API 接口泡孩,那么我們的測(cè)試策略應(yīng)該是:

  • 針對(duì)這 3 個(gè) API 接口,分別基于邊界值和等價(jià)類方法設(shè)計(jì)測(cè)試用例并執(zhí)行寺谤;
  • 在測(cè)試執(zhí)行過(guò)程中仑鸥,啟用代碼覆蓋率統(tǒng)計(jì);
  • 假設(shè)測(cè)試完成后代碼行覆蓋率是 80%变屁,那么我們就需要找到那些還沒(méi)有被執(zhí)行到的 20% 的代碼行眼俊。
    比如圖 中代碼的第 242 行就是沒(méi)有被執(zhí)行到,分析代碼邏輯后發(fā)現(xiàn)粟关,我們需要構(gòu)造“expected!=actual”才能覆蓋這個(gè)未能執(zhí)行的代碼行疮胖;
基于代碼覆蓋率指導(dǎo)測(cè)試用例設(shè)計(jì)的示例.png
  • 最終我們要保證代碼覆蓋率達(dá)到既定的要求,比如行覆蓋率達(dá)到 100%闷板,完成 API 測(cè)試澎灸。

而當(dāng)我們采用微服務(wù)架構(gòu)時(shí),原本的單體應(yīng)用會(huì)被拆分成多個(gè)獨(dú)立模塊遮晚,也就是很多個(gè)獨(dú)立的 service性昭,原本單體應(yīng)用的全局功能將會(huì)由這些拆分得到的 API 共同協(xié)作完成。

比如县遣,對(duì)于上面這個(gè)例子糜颠,沒(méi)有微服務(wù)化之前汹族,一共有 3 個(gè) API 接口,假定現(xiàn)在采用微服務(wù)架構(gòu)其兴,該系統(tǒng)被拆分成了 10 個(gè)獨(dú)立的 service顶瞒,如果每個(gè) service 平均對(duì)外暴露 3 個(gè) API 接口,那么總共需要測(cè)試的 API 接口數(shù)量就多達(dá) 30 個(gè)忌警。

如果我還按照傳統(tǒng)的 API 測(cè)試策略來(lái)測(cè)試這些 API搁拙,那么測(cè)試用例的數(shù)量就會(huì)非常多,過(guò)多的測(cè)試用例往往就需要耗費(fèi)大量的測(cè)試執(zhí)行時(shí)間和資源法绵。

但是箕速,在互聯(lián)網(wǎng)模式下,產(chǎn)品發(fā)布的周期往往是以“天”甚至是以“小時(shí)”為單位的朋譬,留給測(cè)試的執(zhí)行時(shí)間非常有限盐茎,所以微服務(wù)化后 API 測(cè)試用例數(shù)量的顯著增長(zhǎng)就對(duì)測(cè)試發(fā)起了巨大的挑戰(zhàn)。這時(shí)徙赢,我們迫切需要找到一種既能保證 API 質(zhì)量字柠,又能減少測(cè)試用例數(shù)量的測(cè)試策略。

2狡赐、微服務(wù)之間的耦合關(guān)系
微服務(wù)化后窑业,服務(wù)與服務(wù)間的依賴也可能會(huì)給測(cè)試帶來(lái)不小的挑戰(zhàn)。

如圖所示枕屉,假定我們的被測(cè)對(duì)象是 Service T常柄,但是 Service T 的內(nèi)部又調(diào)用了 Service X 和 Service Y。此時(shí)搀擂,如果 Service X 和 Service Y 由于各種原因處于不可用的狀態(tài)西潘,那么此時(shí)就無(wú)法對(duì) Service T 進(jìn)行完整的測(cè)試。

API 之間的耦合示例.png

方法:將 Service T 的測(cè)試與 Service X 和 Service Y 解耦

解耦的方式通常就是實(shí)現(xiàn) Mock Service 來(lái)代替被依賴的真實(shí) Service哨颂。實(shí)現(xiàn)這個(gè) Mock Service 的關(guān)鍵點(diǎn)就是要能夠模擬真實(shí) Service 的 Request 和 Response喷市。

基于消費(fèi)者契約的 API 測(cè)試
核心思想是:只測(cè)試那些真正被實(shí)際使用到的 API 調(diào)用,如果沒(méi)有被使用到的威恼,就不去測(cè)試品姓。

假設(shè)圖中的 Service A、Service B 和 Service T 是微服務(wù)拆分后的三個(gè) Service沃测,其中 Service T 是被測(cè)試對(duì)象缭黔,進(jìn)一步假定 Service T 的消費(fèi)者(也就是使用者)一共有兩個(gè),分別是 Service A 和 Service B蒂破。

Service A馏谨、Service B 和 Service T 的關(guān)系.png

按照傳統(tǒng)的 API 測(cè)試策略,當(dāng)我們需要測(cè)試 Service T 時(shí)附迷,需要找到所有可能的參數(shù)組合依次對(duì) Service T 進(jìn)行調(diào)用惧互,同時(shí)結(jié)合 Service T 的代碼覆蓋率進(jìn)一步補(bǔ)充遺漏的測(cè)試用例哎媚。
但是這樣的話測(cè)試用例的數(shù)量會(huì)非常多,那我們就需要思考喊儡,如何既能保證 Service T 的質(zhì)量拨与,又不需要覆蓋全部可能的測(cè)試用例。

仔細(xì)想一下艾猜,會(huì)發(fā)現(xiàn) Service T 的使用者是確定的买喧,只有 Service A 和 Service B,如果可以把 Service A 和 Service B 對(duì) Service T 所有可能的調(diào)用方式都測(cè)試到匆赃,那么就一定可以保證 Service T 的質(zhì)量淤毛。即使存在某些 Service T 的其他調(diào)用方式有出錯(cuò)的可能性,那也不會(huì)影響整個(gè)系統(tǒng)的功能算柳,因?yàn)檫@個(gè)系統(tǒng)中并沒(méi)有其他 Service 會(huì)以這種可能出錯(cuò)的方式來(lái)調(diào)用 Service T低淡。

從本質(zhì)上來(lái)講,這樣的測(cè)試用例集合其實(shí)就是瞬项,Service T 可以對(duì)外提供的服務(wù)的契約蔗蹋,所以我們把這個(gè)測(cè)試用例的集合稱為“基于消費(fèi)者契約的 API 測(cè)試”。

那么接下來(lái)囱淋,我們要解決的問(wèn)題就是:如何才能找到 Service A 和 Service B 對(duì) Service T 的所有可能調(diào)用了猪杭。其實(shí)這也很簡(jiǎn)單,在邏輯結(jié)構(gòu)上妥衣,我們只要在 Service T 前放置一個(gè)代理胁孙,所有進(jìn)出 Service T 的 Request 和 Response 都會(huì)經(jīng)過(guò)這個(gè)代理,并被記錄成 JSON 文件称鳞,也就構(gòu)成了 Service T 的契約。

收集消費(fèi)者契約的邏輯原理.png

在實(shí)際項(xiàng)目中稠鼻,我們不可能在每個(gè) Service 前去放置這樣一個(gè)代理冈止。但是,微服務(wù)架構(gòu)中往往會(huì)存在一個(gè)叫作 API Gateway 的組件候齿,用于記錄所有 API 之間相互調(diào)用關(guān)系的日志熙暴,我們可以通過(guò)解析 API Gateway 的日志分析得到每個(gè) Service 的契約。

補(bǔ)充知識(shí):API Gateway 一般是作為整個(gè)微服務(wù)的入口慌盯,做一些權(quán)限校驗(yàn)周霉,路由功能,并不是每個(gè)服務(wù)間都存在的亚皂,只有面向客戶端的服務(wù)才會(huì)有這一層俱箱。服務(wù)間的內(nèi)部調(diào)用不走API Gateway 。

微服務(wù)測(cè)試的依賴解耦和 Mock Service
實(shí)現(xiàn) Mock Service 的關(guān)鍵灭必,就是要能夠模擬被替代 Service 的 Request 和 Response狞谱。

此時(shí)我們已經(jīng)拿到了契約乃摹,契約的本質(zhì)就是 Request 和 Response 的組合,具體的表現(xiàn)形式往往是 JSON 文件跟衅,此時(shí)我們就可以用該契約的 JSON 文件作為 Mock Service 的依據(jù)孵睬,也就是在收到什么 Request 的時(shí)候應(yīng)該回復(fù)什么 Response。

下圖 解釋了這一關(guān)系伶跷,當(dāng)用 Service X 的契約啟動(dòng) Mock Service X 后掰读,原本真實(shí)的 Service X 將被 Mock Service X 替代,也就解耦了服務(wù)之間的依賴

基于 Mock Service 解決 API 之間的調(diào)用依賴.png
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末叭莫,一起剝皮案震驚了整個(gè)濱河市蹈集,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌食寡,老刑警劉巖雾狈,帶你破解...
    沈念sama閱讀 218,682評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異抵皱,居然都是意外死亡善榛,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,277評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)呻畸,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)移盆,“玉大人,你說(shuō)我怎么就攤上這事伤为≈溲” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,083評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵绞愚,是天一觀的道長(zhǎng)叙甸。 經(jīng)常有香客問(wèn)我,道長(zhǎng)位衩,這世上最難降的妖魔是什么裆蒸? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,763評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮糖驴,結(jié)果婚禮上僚祷,老公的妹妹穿的比我還像新娘。我一直安慰自己贮缕,他們只是感情好辙谜,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,785評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著感昼,像睡著了一般装哆。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,624評(píng)論 1 305
  • 那天烂琴,我揣著相機(jī)與錄音爹殊,去河邊找鬼。 笑死奸绷,一個(gè)胖子當(dāng)著我的面吹牛梗夸,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播号醉,決...
    沈念sama閱讀 40,358評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼反症,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了畔派?” 一聲冷哼從身側(cè)響起铅碍,我...
    開(kāi)封第一講書(shū)人閱讀 39,261評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎线椰,沒(méi)想到半個(gè)月后胞谈,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,722評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡憨愉,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年烦绳,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片配紫。...
    茶點(diǎn)故事閱讀 40,030評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡径密,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出躺孝,到底是詐尸還是另有隱情享扔,我是刑警寧澤,帶...
    沈念sama閱讀 35,737評(píng)論 5 346
  • 正文 年R本政府宣布植袍,位于F島的核電站惧眠,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏于个。R本人自食惡果不足惜锉试,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,360評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望览濒。 院中可真熱鬧,春花似錦拖云、人聲如沸贷笛。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,941評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)乏苦。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間汇荐,已是汗流浹背洞就。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,057評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留掀淘,地道東北人旬蟋。 一個(gè)月前我還...
    沈念sama閱讀 48,237評(píng)論 3 371
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像革娄,于是被迫代替她去往敵國(guó)和親倾贰。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,976評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容