在之前寫(xiě)的《契約測(cè)試之Pact By Example》中,我曾提到會(huì)再寫(xiě)一篇文章,來(lái)聊聊如何正確地認(rèn)識(shí)和理解契約測(cè)試(好吧,至少是我認(rèn)為的"正確地")影斑。但在隨后的一年多時(shí)間里,對(duì)契約測(cè)試的討論漸漸淡出了我的視野机打。我的理解是矫户,隨著微服務(wù)的大行其道,契約測(cè)試作為帶刀護(hù)衛(wèi)姐帚,已經(jīng)深入人心了吏垮,所以沒(méi)必要再去炒這碗冷飯障涯,就像現(xiàn)在已經(jīng)沒(méi)有誰(shuí)會(huì)再來(lái)碼字吹Selenium一樣(...請(qǐng)相信罐旗,我一定不是因?yàn)閼胁胚@么說(shuō)的o(* ̄3 ̄)o)膳汪。
然而,在最近參加的一次面向Dev的后端分享的討論中九秀,我意外的發(fā)現(xiàn)遗嗽,契約測(cè)試作為構(gòu)建微服務(wù)重要的一環(huán)工程實(shí)踐,雖然確實(shí)已經(jīng)被團(tuán)隊(duì)原生接受鼓蜒,但對(duì)于契約測(cè)試的理解痹换,還存在一些認(rèn)識(shí)上的盲點(diǎn),特別是當(dāng)契約測(cè)試與集成測(cè)試都弹、接口測(cè)試一起討論的時(shí)候娇豫,理解的偏差往往會(huì)被放大不少街望。所以封拧,我想必要的碼點(diǎn)字显蝌,分享一下我對(duì)契約測(cè)試的理解妈拌,還是有益的奈嘿。
"契約測(cè)試艰匙,是建立在服務(wù)的消費(fèi)者和生產(chǎn)者之間的......"(此處省略廢話N多字)狞悲,如果您要繼續(xù)看下去火欧,請(qǐng)注意:
- 以下的內(nèi)容不會(huì)涉及基本的契約測(cè)試概念咪辱,比如消費(fèi)者振劳、生產(chǎn)者、契約油狂、消費(fèi)者驅(qū)動(dòng)等等历恐,如果您對(duì)這些基本概念還不是很清楚,建議您可以花點(diǎn)兒時(shí)間先google一下专筷,當(dāng)然夹供,Pact的官方文檔可以是一個(gè)很好的開(kāi)始;
- 以下的內(nèi)容不會(huì)涉及具體的契約測(cè)試編寫(xiě)和執(zhí)行步驟仁堪,相關(guān)的內(nèi)容哮洽,您可以參看我之前的文章《契約測(cè)試之Pact By Example》;
- 如果您之前在任何地方弦聂、通過(guò)任何方式鸟辅,看到過(guò)一些我對(duì)契約測(cè)試的觀點(diǎn)的分享,并且覺(jué)得我就是在胡說(shuō)八道莺葫,那您也不用看下去了匪凉,因?yàn)楹竺娑际呛f(shuō)十六道,而已捺檬;
關(guān)于測(cè)試的表述
在聊契約測(cè)試之前再层,讓我們先來(lái)說(shuō)一些平時(shí)看似毫不起眼的小話題---"測(cè)試的表述"。
"我們可以在E2E測(cè)試中覆蓋這個(gè)場(chǎng)景,而不是單元測(cè)試..."
或者
"你們的E2E測(cè)試是怎么做的聂受?..."
這里的E2E測(cè)試
可能經(jīng)常出現(xiàn)在我們的日常交流中蒿秦,那你知道它的準(zhǔn)確含義嗎?答案是沒(méi)有含義蛋济!它基本等價(jià)于你們一伙人去食堂吃飯(...笑啥棍鳖,俺就是食堂黨,咋的M肼谩)渡处,A:"今天吃啥?"祟辟,B:"新鮮的"医瘫。新鮮的啥?炒飯旧困?面條醇份?餃子?套餐叮喳?......
E2E被芳,End To End,端到端馍悟,字面意思簡(jiǎn)單明了畔濒,但它只是一個(gè)副詞(組),而不是一種測(cè)試類型锣咒。所以侵状,我們真正想表述的,可能是E2E API Test毅整。那么"E2E API Test"就完整的表述了一項(xiàng)測(cè)試活動(dòng)了嗎趣兄?不是的!E2E
表示的是測(cè)試方式悼嫉,API
表示的是被測(cè)對(duì)象艇潭,但這里,我們還缺少被測(cè)對(duì)象的被測(cè)屬性戏蔑,比如蹋凝,F(xiàn)unction、Performance, Security等等总棵,所以鳍寂,一個(gè)比較完整的表述,往往可以是這樣的:
當(dāng)然情龄,平常的交流中迄汛,一般不會(huì)這么文縐縐地去摳字眼捍壤,因?yàn)槲覀儽舜硕记宄懻搯?wèn)題的上下文,這點(diǎn)很重要鞍爱。特別是針對(duì)E2E測(cè)試
這樣的表述鹃觉。比如,我們有一個(gè)前后端分離硬霍、后端是微服務(wù)集群的系統(tǒng)應(yīng)用帜慢,同樣的E2E測(cè)試
可能就代表著完全不同的測(cè)試活動(dòng):
如果從更多的維度來(lái)思考笼裳,比如套上測(cè)試四象限的模式唯卖,那么對(duì)于測(cè)試活動(dòng)的表述,還會(huì)有更多考量躬柬。但今天的主題是關(guān)于契約測(cè)試的拜轨,所以就不過(guò)多的展開(kāi)了。為什么要在討論契約測(cè)試之前來(lái)廢話"測(cè)試表述"呢允青?因?yàn)槠跫s測(cè)試其實(shí)是多種測(cè)試方式的和思維的復(fù)合產(chǎn)物橄碾,比如,契約測(cè)試是E2E的測(cè)試嗎颠锉?還是說(shuō)是基于Mock的法牲?契約測(cè)試是服務(wù)的接口測(cè)試還是集成測(cè)試?等等琼掠。所以拒垃,如果對(duì)這些基本的測(cè)試概念不是很清楚的,很容易迷失在契約測(cè)試的理念中瓷蛙。
為什么要做契約測(cè)試悼瓮?
為什么要做契約測(cè)試?"因?yàn)槲覀兪俏⒎?wù)"艰猬?(╬ ̄皿 ̄)=○
很多回答這個(gè)問(wèn)題的答案横堡,都關(guān)注在契約測(cè)試的目的上。那么冠桃,什么是契約測(cè)試的目的呢命贴?簡(jiǎn)單來(lái)說(shuō),契約測(cè)試就是為了發(fā)現(xiàn)契約破壞(Contract Breaking)而進(jìn)行的測(cè)試活動(dòng)食听。如果你使用過(guò)Pact或者Spring Cloud Contract胸蛛,你會(huì)發(fā)現(xiàn),契約測(cè)試本身也是通過(guò)調(diào)用Provider的API接口來(lái)獲取Response碳蛋,再與契約文件中期望的結(jié)果做對(duì)比胚泌,從而驗(yàn)證契約是否正確。形式上肃弟,這和我們的API接口測(cè)試玷室,或者針對(duì)功能的集成測(cè)試(以下簡(jiǎn)稱集成測(cè)試零蓉,因?yàn)槲覀冞@里不討論API的安全、性能等問(wèn)題)是非常類似的穷缤。換句話說(shuō)敌蜂,我們通過(guò)API的接口測(cè)試或者集成測(cè)試,也能達(dá)到檢查契約的目的津肛,那為什么還要做契約測(cè)試呢章喉?這種思考邏輯是完全正確的,也是為什么很多初學(xué)者都認(rèn)為契約測(cè)試沒(méi)有必要的原因身坐。
那再問(wèn)秸脱,為什么我們還要做契約測(cè)試呢?真正能夠回答這個(gè)問(wèn)題的部蛇,不是契約測(cè)試的目的摊唇,而是契約測(cè)試可以帶來(lái)的價(jià)值!
契約測(cè)試的價(jià)值
那什么是契約測(cè)試的價(jià)值呢涯鲁?要說(shuō)清楚契約測(cè)試的價(jià)值巷查,就需要準(zhǔn)確認(rèn)識(shí)契約測(cè)試的精髓--"消費(fèi)者驅(qū)動(dòng)"。
消費(fèi)者驅(qū)動(dòng)的字面含義抹腿,大家都清楚岛请,但往往容易忽略的是被驅(qū)動(dòng)的對(duì)象
。在討論契約測(cè)試的范疇里警绩,"消費(fèi)者驅(qū)動(dòng)"述及的對(duì)象是契約崇败,而不是契約測(cè)試。
當(dāng)某個(gè)provider正常上線后房蝉,某個(gè)consumer需要消費(fèi)這個(gè)provider的服務(wù)僚匆,那么應(yīng)該由consumer來(lái)提出期望建立它們之間的契約測(cè)試。因?yàn)椋?code>契約測(cè)試搭幻,形式上咧擂,雖然測(cè)試的是provider,但檀蹋,價(jià)值上松申,保證的卻是consumer的業(yè)務(wù)。如果consumer對(duì)自己都不上心俯逾,你還期望provider來(lái)時(shí)刻關(guān)注你的死活嗎贸桶?別笑,在跨團(tuán)隊(duì)的微服務(wù)體系下桌肴,這些都是真切的痛點(diǎn)皇筛。
理清了消費(fèi)者驅(qū)動(dòng),就讓我們來(lái)看看契約測(cè)試真正的價(jià)值吧坠七。一個(gè)經(jīng)典的案例:
在上圖一個(gè)簡(jiǎn)單的消費(fèi)關(guān)系中水醋,provider為consumer A旗笔,B,C提供服務(wù)拄踪。provider自己提供的schema包含name
,age
和gender
三個(gè)簡(jiǎn)單的字段蝇恶。請(qǐng)注意,這份包含name惶桐,age和gender的JSON撮弧,其本身,只是一個(gè)schema姚糊,并不是任何契約贿衍。契約一定是成對(duì)存在的,沒(méi)有確切consumer的交互定義叛拷,只是schema舌厨,不是契約
岂却。一個(gè)列子忿薇,中介打印了一份合同,上面寫(xiě)好了房屋租賃的全部信息躏哩,但在房東和租客都簽字之前署浩,這份"合同"并不具有任何效力,所以它根本就不是一份有意義的合同扫尺,法律上筋栋,它叫"要約"。(...感謝我大學(xué)的法律老師正驻,我居然還記得這個(gè)詞兒)
現(xiàn)在弊攘,這里有三份契約(對(duì)應(yīng)的,就應(yīng)該有三份契約測(cè)試)姑曙,consumer A消費(fèi)provider的age和gender襟交,consumer B消費(fèi)name、age和gender伤靠,consumer C消費(fèi)name和gender捣域。就目前provider提供的schema來(lái)說(shuō),沒(méi)有任何問(wèn)題宴合,大家相安無(wú)事焕梅。
某日,因?yàn)闃I(yè)務(wù)需求卦洽,consumer C期望provider提供更加詳細(xì)的name信息贞言,包括firstName和lastName。這個(gè)需求對(duì)provider并不困難阀蒂,所以该窗,provider打算對(duì)schema做類似下面的修改打肝。
這樣的修改,很明顯
挪捕,對(duì)consumer C是需要的粗梭,對(duì)consumer A無(wú)所謂,但對(duì)consumer B卻是不可接受的级零,屬于典型的契約破壞断医。此時(shí),provider和consumer B之間的契約測(cè)試就會(huì)掛掉奏纪,從而對(duì)provider提出預(yù)警(至于鉴嗤,剩下的,怎么協(xié)調(diào)和consumer B的兼容問(wèn)題序调,就不是契約測(cè)試關(guān)注的問(wèn)題醉锅,那需要的是團(tuán)隊(duì)間的communication)。
上面這個(gè)示例中的一些細(xì)節(jié)发绢,可以幫助我們發(fā)掘契約測(cè)試的價(jià)值點(diǎn):
"consumer A沒(méi)有使用name硬耍,consumer C沒(méi)有使用age",
基于消費(fèi)者驅(qū)動(dòng)的契約測(cè)試边酒,契約的內(nèi)容由consumer提供经柴,其內(nèi)容體現(xiàn)的是各個(gè)consumer對(duì)provider提供的schema的消費(fèi)需求。這里的需求墩朦,不光包含consumer"需要什么"坯认,還包含consumer"不需要什么"。這是非常有意義的氓涣,因?yàn)楫?dāng)你發(fā)現(xiàn)provider提供的schema的某些部分不被任何consumer消費(fèi)時(shí)牛哺,就代表provider可以對(duì)schema的這些內(nèi)容做任意的修改,完全不必?fù)?dān)心會(huì)影響到任何consumer劳吠。這是契約測(cè)試非常重要的價(jià)值點(diǎn)引润。
"單個(gè)provider多個(gè)consumer",
要最大化的體現(xiàn)契約測(cè)試異于集成測(cè)試的價(jià)值赴背,一定是在"單個(gè)provider對(duì)應(yīng)多個(gè)consumer"的架構(gòu)下來(lái)說(shuō)的椰拒。因?yàn)椋谥挥幸粋€(gè)provider和一個(gè)consumer的架構(gòu)下凰荚,只存在一份契約燃观,對(duì)該契約內(nèi)容的任何修改,對(duì)這對(duì)provider和consumer來(lái)說(shuō)便瑟,都是顯而易見(jiàn)的缆毁,那么就不會(huì)出現(xiàn)契約破壞的情況。說(shuō)人話到涂,就是脊框,如果是consumer提出要修改契約颁督,consumer一定知道改怎么消費(fèi)新的契約內(nèi)容;如果是provider提出修改契約浇雹,對(duì)于唯一的一個(gè)consumer沉御,provider能很方便的告知其將要對(duì)契約的修改。并且昭灵,在這種情況下吠裆,集成測(cè)試往往就已經(jīng)完整的達(dá)到了契約測(cè)試的目的。
而在單個(gè)provider對(duì)應(yīng)多個(gè)consumer的架構(gòu)下烂完,情況就大不一樣了试疙。provider和consumer C之間的契約修改,對(duì)consumer A無(wú)感抠蚣,對(duì)consumer B卻是契約破壞祝旷,對(duì)此,集成測(cè)試是無(wú)能為力的嘶窄。仔細(xì)來(lái)看怀跛,這里有4個(gè)service,就會(huì)有4個(gè)集成測(cè)試护侮。但每個(gè)集成測(cè)試都只會(huì)關(guān)注自己的業(yè)務(wù)正確性敌完,具體來(lái)說(shuō):
consumer A,因?yàn)椴皇苡绊懷虺酰訟的集成測(cè)試沒(méi)有任何變化;
consumer C什湘,因?yàn)槭瞧跫s修改的提出者长赞,所以它會(huì)在provider提供新的schema后修改自己的集成測(cè)試,沒(méi)有問(wèn)題闽撤;
provider得哆,如果接受了consumer C的需求,大搖大擺地修改了schema哟旗,它也會(huì)相應(yīng)的修改自己的集成測(cè)試贩据,因?yàn)閷?duì)provider來(lái)說(shuō),這個(gè)變更是正常的業(yè)務(wù)需求闸餐,也沒(méi)有問(wèn)題饱亮;
consumer B,最倒霉舍沙,啥都沒(méi)干就掛了近上,當(dāng)然,它的集成測(cè)試會(huì)捕捉到這個(gè)failure拂铡,但那都是在provider的契約破壞生效之后的事情了壹无,能做的也只有亡羊補(bǔ)牢葱绒。
可見(jiàn),雖然4個(gè)集成測(cè)試都各司其職斗锭,但都不能對(duì)這個(gè)契約破壞的問(wèn)題做到防患于未然地淀!只有契約測(cè)試,才是這個(gè)問(wèn)題的最佳答案岖是!這就是契約測(cè)試最大的價(jià)值骚秦,它只會(huì)在"單provider多consumer"的環(huán)境下(這是微服務(wù)的常見(jiàn)場(chǎng)景,但不是必然場(chǎng)景)璧微,才能發(fā)揮出來(lái)作箍。
"很顯然,對(duì)consumer A無(wú)害前硫,但對(duì)consumer B卻是契約破壞"胞得,
"很顯然"
,僅僅是對(duì)于我們這個(gè)簡(jiǎn)單得不能再簡(jiǎn)單的示例而言屹电,真正的業(yè)務(wù)場(chǎng)景下阶剑,特別是一些復(fù)雜的微服務(wù)集群,又或者是一些時(shí)間跨度很長(zhǎng)的系統(tǒng)危号,對(duì)于某個(gè)provider牧愁,到底有多少個(gè)consumer?而provider的每一處修改外莲,又到底會(huì)對(duì)哪些consumer的契約造成怎樣的影響猪半?這些往往都是很難確定的問(wèn)題。我最近所在的一個(gè)集團(tuán)項(xiàng)目上偷线,一個(gè)搜索地址的基礎(chǔ)服務(wù)provider磨确,有十個(gè)左右的consumer,其中有八個(gè)consumer沒(méi)有契約測(cè)試声邦,就不清楚它們對(duì)provider的API具體是如何消費(fèi)的乏奥,所以每次provider要更新,就得八方去通知這些consumer的團(tuán)隊(duì)來(lái)做回歸測(cè)試亥曹。有時(shí)邓了,一點(diǎn)小小的修改,回歸測(cè)試一分鐘就可以搞定媳瞪,但人肉聯(lián)系各個(gè)團(tuán)隊(duì)卻會(huì)花上好幾天......
如果每個(gè)consumer都能和provider建立契約測(cè)試(這里我們暫且不考慮負(fù)載和去重的問(wèn)題)骗炉,通過(guò)類似Pact Broker這樣的實(shí)踐,我們就能很好的解決這些效率問(wèn)題材失。
OK痕鳍,理解透契約測(cè)試的這些價(jià)值后,對(duì)于"要不要做契約測(cè)試?"笼呆、"誰(shuí)來(lái)做契約測(cè)試熊响?"這些問(wèn)題,相信你就不再疑惑了诗赌。想再次強(qiáng)調(diào)一下的是汗茄,契約測(cè)試很多情況下基于微服務(wù)而生,但并不代表每個(gè)微服務(wù)都一定需要契約測(cè)試铭若。相對(duì)的洪碳,一些傳統(tǒng)的單體服務(wù),它的架構(gòu)設(shè)計(jì)和部署實(shí)施叼屠,完全和微服務(wù)的理念相反瞳腌,但它提供的服務(wù)卻被眾多的下游消費(fèi)者使用,那么這樣的服務(wù)镜雨,也有很強(qiáng)的契約測(cè)試需求嫂侍。所以,千萬(wàn)不要把契約測(cè)試和微服務(wù)做"死綁定"荚坞,一定要基于服務(wù)的業(yè)務(wù)來(lái)考慮策略挑宠。
契約測(cè)試和接口測(cè)試、集成測(cè)試的區(qū)別
"契約測(cè)試和接口測(cè)試颓影、集成測(cè)試的區(qū)別"各淀,從2015年我第一次在BQConf講契約測(cè)試,到寫(xiě)這篇文章之前诡挂,最近一次和別人討論契約測(cè)試碎浇,這都是一個(gè)一直被提起的問(wèn)題。在上面的內(nèi)容中咆畏,其實(shí)已經(jīng)或多或少的提到了相關(guān)的內(nèi)容南捂。由于具體的測(cè)試方式,都是"調(diào)用API驗(yàn)證Response"旧找,契約測(cè)試、接口測(cè)試麦牺、集成測(cè)試經(jīng)常被放在一起來(lái)進(jìn)行比較钮蛛,甚至質(zhì)疑彼此。
先讓我們來(lái)看看接口測(cè)試和集成測(cè)試剖膳。說(shuō)實(shí)話魏颓,對(duì)于測(cè)試?yán)碚摵粚?shí)的QA來(lái)說(shuō),這里應(yīng)該沒(méi)有任何問(wèn)題的吱晒,因?yàn)榻涌跍y(cè)試和集成測(cè)試甸饱,它們壓根兒就是從完全不同的維度來(lái)描述測(cè)試活動(dòng)的。
前面說(shuō)過(guò),如果要完整的描述一個(gè)測(cè)試活動(dòng)叹话,至少需要考慮三個(gè)內(nèi)容:測(cè)試方式偷遗、被測(cè)對(duì)象、被測(cè)屬性驼壶。然而氏豌,"接口測(cè)試"和"集成測(cè)試",顯然热凹,都是我們根據(jù)上下文使用的簡(jiǎn)稱泵喘,更準(zhǔn)確的:
測(cè)試方式 | 被測(cè)對(duì)象 | 被測(cè)屬性 | |
---|---|---|---|
接口測(cè)試 | 調(diào)用API接口 | 只能是API | ... |
集成測(cè)試 | ... | ... | 肯定是被測(cè)對(duì)象在于外部依賴集成時(shí)的行為表現(xiàn) |
接口測(cè)試
- 被測(cè)屬性 --- 不定,可以是被測(cè)對(duì)象的性能或安全行為般妙,但根據(jù)上下文纪铺,默認(rèn)是功能行為;
集成測(cè)試
- 測(cè)試方式 --- 不定碟渺,可以直接進(jìn)行E2E的測(cè)試鲜锚,也可以進(jìn)行基于Mock的測(cè)試;
- 被測(cè)對(duì)象 --- 不定止状,可以是UI烹棉,也可以是API,但根據(jù)上下文怯疤,默認(rèn)是API浆洗;
所以,基于不同的維度集峦,我們有"接口測(cè)試"和"集成測(cè)試"的表述伏社,但,當(dāng)放在和契約測(cè)試來(lái)討論的時(shí)候塔淤,它們描述的可能是同樣的測(cè)試活動(dòng)摘昌。即,通過(guò)調(diào)用API接口高蜂,來(lái)測(cè)試API的功能行為聪黎。
這里,想強(qiáng)調(diào)一下集成測(cè)試中的"集成"备恤。對(duì)于傳統(tǒng)的瀑布開(kāi)發(fā)模式稿饰,對(duì)應(yīng)的測(cè)試流程按照測(cè)試級(jí)別(Test Level)劃分,一般是:?jiǎn)卧獪y(cè)試 -> 集成測(cè)試 -> 系統(tǒng)測(cè)試 -> 驗(yàn)收測(cè)試露泊,這是"集成測(cè)試"早期的由來(lái)喉镰。
那會(huì)兒的應(yīng)用,往往是龐大的單體服務(wù)惭笑,服務(wù)內(nèi)部有分工明細(xì)侣姆、邊界分明的"模塊"生真。這些模塊被并行開(kāi)發(fā),就緒后就會(huì)進(jìn)行彼此集成捺宗。集成的對(duì)象柱蟀,一般可以簡(jiǎn)單分為:邏輯模塊、數(shù)據(jù)庫(kù)模塊偿凭、外部服務(wù)模塊产弹。比如,在上古時(shí)代弯囊,對(duì)數(shù)據(jù)庫(kù)的操作是比較繁瑣的痰哨,開(kāi)發(fā)人員往往需要自己組裝SQL語(yǔ)句,然后封裝成模塊來(lái)供上層調(diào)用匾嘱。單元測(cè)試可以保證這些模塊自己的邏輯正確斤斧,但像"模塊中的各個(gè)函數(shù)接受的參數(shù)個(gè)數(shù)和參數(shù)類型是否和模塊使用者的需求相匹配"這樣的問(wèn)題,就需要集成測(cè)試來(lái)確保(集成不等于集成測(cè)試霎烙,內(nèi)容所限撬讽,我就不過(guò)多說(shuō)明了)。這些測(cè)試都是發(fā)生在單體服務(wù)內(nèi)部的悬垃,類似于現(xiàn)在的組件測(cè)試游昼。
如今,微服務(wù)的設(shè)計(jì)尝蠕,將不同業(yè)務(wù)的"模塊"拆分成了不同的服務(wù)烘豌,各個(gè)服務(wù)都是高內(nèi)聚的。以Spring為例看彼,Controller -> Service -> Repository廊佩,內(nèi)部垂直劃分,簡(jiǎn)單明了靖榕。像上面提到的手寫(xiě)SQL這樣的數(shù)據(jù)持久化工作标锄,已經(jīng)基本不存在了,取而代之的是像spring-boot-starter-data-jpa或spring-boot-starter-data-mongodb這樣功能強(qiáng)大茁计、方便易用的公共組件料皇,最重要的,這樣的公共組件星压,一般都有很高的官方質(zhì)量保證的瓶蝴。所以,結(jié)論就是租幕,在上古時(shí)代的那種傳統(tǒng)的集成測(cè)試,在微服務(wù)的體系下拧簸,已經(jīng)基本不需要了劲绪。
而對(duì)于單個(gè)微服務(wù)的質(zhì)量保障,特別是當(dāng)這個(gè)微服務(wù)有外部集成的時(shí)候,比如數(shù)據(jù)庫(kù)或者外部服務(wù)贾富,我們?nèi)匀恍枰M(jìn)行檢查外部集成的測(cè)試歉眷。再結(jié)合微服務(wù)業(yè)務(wù)的單一性,我們可以很自然的將這種"檢查外部集成的測(cè)試"合并到API的接口功能測(cè)試中颤枪。說(shuō)人話就是汗捡,對(duì)于微服務(wù),只進(jìn)行API的接口功能測(cè)試畏纲,既涵蓋對(duì)被測(cè)服務(wù)領(lǐng)域邏輯的檢查扇住,又覆蓋其對(duì)外部集成的檢查。
當(dāng)然盗胀,這里已經(jīng)討論到了微服務(wù)測(cè)試策略了艘蹋,我就不再過(guò)多展開(kāi)了。話收回來(lái)票灰,如果要和契約測(cè)試進(jìn)行區(qū)別比較的話女阀,我們只用考慮功能性的API接口測(cè)試就可以了。
理清了接口測(cè)試和集成測(cè)試的內(nèi)部姻緣(下面我統(tǒng)稱功能測(cè)試)屑迂,我們就最后來(lái)說(shuō)說(shuō)它們和契約測(cè)試的區(qū)別吧~
其實(shí)浸策,上面那個(gè)示例,已經(jīng)很好的展現(xiàn)了它們的區(qū)別惹盼,我就不過(guò)多解釋了庸汗,簡(jiǎn)單來(lái)說(shuō):
功能測(cè)試關(guān)注的是provider的實(shí)現(xiàn)正確體現(xiàn)其設(shè)計(jì),契約測(cè)試關(guān)注的是provider的實(shí)現(xiàn)(當(dāng)然逻锐,肯定也包括設(shè)計(jì))滿足每一個(gè)consumer的需求夫晌。注意,功能測(cè)試只關(guān)注provider自身昧诱,契約測(cè)試關(guān)注每一個(gè)consumer晓淀;
功能測(cè)試的測(cè)試案例,由provider的團(tuán)隊(duì)提供盏档,契約測(cè)試的測(cè)試案例凶掰,基于消費(fèi)者驅(qū)動(dòng),由各個(gè)consumer團(tuán)隊(duì)提供蜈亩;
一個(gè)provider只會(huì)有一個(gè)功能測(cè)試(誰(shuí)要糾結(jié)"一個(gè)功能測(cè)試"是幾個(gè)testcase懦窘,就把TA拖出去槍斃三分鐘),但契約測(cè)試稚配,理論上畅涂,可以無(wú)限,有多少consumer就可以有多少個(gè)契約測(cè)試道川;
同樣的一個(gè)testcase午衰,在功能測(cè)試?yán)锩娉霈F(xiàn)一次立宜,在契約測(cè)試?yán)锩娉霈F(xiàn)N次,它們的含義是完全不同的臊岸。什么含義橙数,自己琢磨琢磨;
一個(gè)testcase帅戒,出現(xiàn)在功能測(cè)試?yán)锩娴瓢铮瑓s沒(méi)有出現(xiàn)在契約測(cè)試?yán)锩妫欠浅S幸饬x的逻住。啥意義钟哥,再自己琢磨琢磨;
功能測(cè)試可以自?shī)首詷?lè)鄙信,契約測(cè)試必須組"對(duì)"上分瞪醋;
契約測(cè)試可以替代集成測(cè)試嗎?
"契約測(cè)試替代集成測(cè)試"装诡,說(shuō)實(shí)話银受,第一次聽(tīng)見(jiàn)這個(gè)說(shuō)法的時(shí)候,我是非常驚訝的鸦采,這得多大的腦洞才能給出這樣的命題呀宾巍!
提示一下,就題論題渔伯,這里的"集成測(cè)試"顶霞,并不全等與上面提到的"功能測(cè)試",僅僅是一般論的集成測(cè)試锣吼。
先來(lái)揣測(cè)一下选浑,為什么會(huì)有這樣的問(wèn)題吧。我們知道玄叠,在Pact(JVM)的實(shí)施過(guò)程中古徒,第一步是在consumer端生成契約文件。這期間读恃,Pact會(huì)根據(jù)自定義的契約隧膘,在consumer端啟動(dòng)一個(gè)mock server(如果你有看源碼,就知道它只是一個(gè)普通的HttpServer實(shí)例)寺惫,consumer向這個(gè)mock server發(fā)送request獲取response疹吃,整個(gè)過(guò)程被記錄成JSON的契約文件。
這個(gè)流程的最后一步西雀,一直有一個(gè)大家樂(lè)于爭(zhēng)論的話題:"要不要對(duì)response的內(nèi)容做斷言檢查萨驶?"。這是一個(gè)很開(kāi)放的問(wèn)題艇肴,沒(méi)有標(biāo)準(zhǔn)的答案篡撵。但我想強(qiáng)調(diào)的是判莉,不加斷言,這一切只是一個(gè)"流程"或者說(shuō)"步驟"育谬,加上斷言,它就是測(cè)試帮哈。是的膛檀,對(duì)consumer來(lái)說(shuō),它就是consumer的一種集成測(cè)試(啥娘侍?"用的是Mock Server咖刃,都沒(méi)有集成真正的provider,為什么叫集成測(cè)試憾筏?" 如果你有這個(gè)問(wèn)題嚎杨,可以再仔細(xì)想想集成測(cè)試的真正含義......)。
以上是解題背景⊙跹現(xiàn)在,讓我們?cè)賮?lái)審一下題吧,"契約測(cè)試可以替代集成測(cè)試嗎孽文?"钱骂,這里,其實(shí)隱藏了很大的一個(gè)意識(shí)盲點(diǎn)黄痪。契約測(cè)試紧帕,描述的測(cè)試活動(dòng),一定是架設(shè)在一對(duì)consumer和provider之間的桅打。那么題目里的集成測(cè)試呢是嗜?你是想替換consumer端的集成測(cè)試?還是想替換provider端的集成測(cè)試挺尾?還是說(shuō)其實(shí)你也不清楚到我想替換哪一端的集成測(cè)試......"不鹅搪!我想說(shuō)的不是兩個(gè)服務(wù)之間的集成的那種測(cè)試,而是整個(gè)系統(tǒng)潦嘶,包括全部上下游服務(wù)涩嚣,集成在一起的集成測(cè)試"......誒,好吧掂僵,那叫系統(tǒng)(E2E)測(cè)試......
還是讓我們回到一般論的集成測(cè)試上來(lái)吧(不然航厚,要說(shuō)的實(shí)在太多了 T_T),無(wú)論是consumer端還是provider端锰蓬,集成測(cè)試的關(guān)注點(diǎn)幔睬,是consumer是否可以正確的消費(fèi)provider的API,這里的"消費(fèi)"包括調(diào)用接口和解析數(shù)據(jù)芹扭。它的被測(cè)對(duì)象麻顶,注意赦抖,一定是consumer,或者說(shuō)辅肾,是一個(gè)服務(wù)作為consumer的角色(因?yàn)槎佑硞€(gè)服務(wù)經(jīng)常既是consumer,又是provider)矫钓。而契約測(cè)試的被測(cè)對(duì)象要尔,一定是provider。好了新娜,這就是問(wèn)題的核心赵辕,其它的細(xì)節(jié),我想就不必再贅述了吧概龄。
關(guān)于Pact和Spring Cloud Contract
"用Pact還是Spring Cloud Contract还惠?",這是另一個(gè)經(jīng)常被討論的話題私杜。它背后折射的卻是另一個(gè)非常重要的概念博弈:契約測(cè)試 vs 基于契約的測(cè)試(契約驅(qū)動(dòng)的測(cè)試)蚕键。
Pact的理念是消費(fèi)者驅(qū)動(dòng)的契約測(cè)試。什么是契約測(cè)試呢歪今?目前嚎幸,我沒(méi)有找到任何"權(quán)威"的定義。其實(shí)寄猩,面向工程實(shí)踐的理念嫉晶,也許根本就沒(méi)有權(quán)威,有的只是最適用于自身的實(shí)踐總結(jié)田篇。即便如此替废,我還是希望以個(gè)人的視角,提供一些解讀:
如果你google搜索contract test泊柬,你得到的第一個(gè)答案肯定是Martin Fowler在2011年的這篇文章椎镣,但遺憾的是,老馬這里討論的契約測(cè)試兽赁,是解決在集成測(cè)試中状答,如何保證測(cè)試替身有效性的問(wèn)題的,它和我們今天討論的契約測(cè)試并不是一回事刀崖。但是惊科,如果拋開(kāi)契約測(cè)試的內(nèi)容,而單論"契約測(cè)試"的定義的話亮钦,老馬的文章其實(shí)表述了一個(gè)很有價(jià)值的點(diǎn)馆截,那就是"契約是需要測(cè)試的",這是非常有意義的。
Pact的官方文檔蜡娶,是另一個(gè)可以幫助我們理解契約測(cè)試的地方混卵。它對(duì)契約測(cè)試給出了這樣的定義:
Contract testing is a way to ensure that services (such as an API provider and a client) can communicate with each other.
,這里面需要關(guān)注的重點(diǎn)是communicate
窖张,它給出了Pact對(duì)契約測(cè)試范疇(scope)的定義幕随。對(duì)于任何以"XXX測(cè)試"命名的測(cè)試活動(dòng),我們都遵循同樣的一個(gè)理解的公理:"XXX"一定是被測(cè)對(duì)象或被測(cè)屬性荤堪。比如合陵,UI測(cè)試,測(cè)試對(duì)象一定是UI澄阳;安全測(cè)試,測(cè)試的一定是被測(cè)對(duì)象的安全表現(xiàn)踏拜;兼容性測(cè)試碎赢,關(guān)注的一定是被測(cè)對(duì)象在兼容性方面的問(wèn)題,等等速梗。同樣的肮塞,"契約測(cè)試",被測(cè)對(duì)象一定是服務(wù)之間的契約姻锁。
好了枕赵,有了這三點(diǎn)重要的理論基礎(chǔ),就讓我們來(lái)具體看看Pact和Spring Cloud Contract(以下簡(jiǎn)稱SCC)的區(qū)別吧位隶。
在上面的圖中拷窜,給出了Pact和SCC具體的使用方式(邏輯路徑)。當(dāng)然涧黄,如果你有一些基本的Pact或SCC的使用經(jīng)驗(yàn)篮昧,就再好不過(guò)了。
Pact笋妥,在consumer端生成契約文件懊昨,發(fā)布到Pact Broker,而后春宣,provider從Pact Broker獲取契約文件酵颁,觸發(fā)provider端執(zhí)行契約測(cè)試。
SCC月帝,實(shí)際生成契約文件的工作是發(fā)生在provider端的躏惋,基于這份契約文件,在provider端嫁赏,生成了Java的測(cè)試案例其掂,這些測(cè)試案例用于provider的功能測(cè)試;而在Consumer端潦蝇,使用同一份契約文件作為Stub款熬,生成了基于WireMock的mock service深寥,consumer可以使用該mock service來(lái)做集成測(cè)試。
可見(jiàn)贤牛,Pact作為消費(fèi)者驅(qū)動(dòng)契約測(cè)試的倡導(dǎo)者惋鹅,真正地實(shí)踐了消費(fèi)者驅(qū)動(dòng)的契約測(cè)試。相對(duì)的殉簸,SCC闰集,既沒(méi)有實(shí)際的將契約作為被測(cè)對(duì)象來(lái)進(jìn)行測(cè)試,更沒(méi)有確實(shí)地實(shí)現(xiàn)"消費(fèi)者驅(qū)動(dòng)"般卑。SCC的做法武鲁,實(shí)際上是基于同一份契約,分別驅(qū)動(dòng)了consumer端的集成測(cè)試和provider端的功能測(cè)試蝠检。所以沐鼠,Pact和SCC的區(qū)別,就在于叹谁,前者做的是"契約測(cè)試"饲梭,后者做的是"基于契約的測(cè)試(契約驅(qū)動(dòng)的測(cè)試)"。
如果有同學(xué)閱讀過(guò)SCC的文檔焰檩,一定會(huì)質(zhì)疑憔涉,SCC明文寫(xiě)著"Spring Cloud Contract Verifier enables Consumer Driven Contract (CDC) development of JVM-based applications",那為什么說(shuō)它沒(méi)有確實(shí)地實(shí)現(xiàn)"消費(fèi)者驅(qū)動(dòng)"呢析苫?因?yàn)樵赟CC的設(shè)計(jì)中兜叨,原始契約文件是在provider端生成的。為了實(shí)現(xiàn)CDC藤违,consumer需要在其本地克隆provider的代碼倉(cāng)庫(kù)浪腐,"借"provider來(lái)生成原始的契約文件。顯然顿乒,在現(xiàn)實(shí)的項(xiàng)目中议街,consumer團(tuán)隊(duì)不可能隨心所欲的獲取到provider代碼倉(cāng)庫(kù)訪問(wèn)權(quán)限,所以有了后來(lái)的璧榄,基于Share Repo的解決方案特漩,來(lái)實(shí)現(xiàn)契約的共享(編輯和使用)。所以說(shuō)骨杂,從最初的設(shè)計(jì)思想來(lái)看涂身,SCC并沒(méi)有像Pact那樣,"實(shí)實(shí)在在"地實(shí)踐了消費(fèi)者驅(qū)動(dòng)的契約測(cè)試搓蚪。
那么蛤售,到底是選擇Pact(契約測(cè)試)還是SCC(基于契約的測(cè)試)呢?答案是"按需取舍"。
比較Pact和SCC的目的悴能,并不是區(qū)別彼此的好壞長(zhǎng)短揣钦,而是闡述它們各自不同的測(cè)試?yán)砟睢act的價(jià)值點(diǎn)漠酿,前面已經(jīng)說(shuō)過(guò)了冯凹,SCC,雖然做的并不是真正的契約測(cè)試炒嘲,但它通過(guò)共享(同一份)契約的方式宇姚,實(shí)現(xiàn)了微服務(wù)測(cè)試中,consumer和provider之間E2E集成測(cè)試的解耦夫凸,這在實(shí)際項(xiàng)目中浑劳,也是有重要的現(xiàn)實(shí)意義的。感興趣的同學(xué)可以自己下來(lái)多研究研究夭拌,我就不在這里擴(kuò)展了呀洲。
一些問(wèn)題
至此,在我看來(lái)啼止,契約測(cè)試相關(guān)的認(rèn)識(shí)難點(diǎn),就已經(jīng)基本解讀到了兵罢。但在結(jié)束全文之前献烦,有兩個(gè)問(wèn)題,我還想再闡述一下:
consumer端的集成測(cè)試需要做到什么程度卖词?
對(duì)于Pact巩那,前面提到,在consumer端生成契約文件的時(shí)候此蜈,加上斷言語(yǔ)句后即横,就"構(gòu)成"了consumer端的集成測(cè)試。這個(gè)集成測(cè)試裆赵,從Pact的角度來(lái)說(shuō)东囚,是可選的,它的目的是保證consumer端生成的契約文件本身是正確的战授。但從consumer的角度來(lái)說(shuō)页藻,要不要進(jìn)行這一層級(jí)的集成測(cè)試,取決于consumer團(tuán)隊(duì)自己的測(cè)試策略植兰。我想說(shuō)的是份帐,如果要進(jìn)行這一層級(jí)的集成測(cè)試,請(qǐng)一定合理把握你的測(cè)試粒度和測(cè)試范疇楣导。
測(cè)試粒度废境,由于這里的集成測(cè)試是和契約測(cè)試強(qiáng)綁定的,如果為了增加集成測(cè)試的覆蓋率而設(shè)定過(guò)小的測(cè)試粒度,會(huì)大大增加契約測(cè)試的測(cè)試案例噩凹。而其中的一些測(cè)試案例巴元,對(duì)于關(guān)注功能的集成測(cè)試來(lái)說(shuō),可能是不同的等價(jià)類栓始,但對(duì)關(guān)注schema的契約測(cè)試來(lái)說(shuō)务冕,則完全可能是相同的等價(jià)類,從而造成測(cè)試冗余幻赚。所以禀忆,合理的把握測(cè)試粒度,是非常重要的落恼。當(dāng)然箩退,就個(gè)人意見(jiàn),我是反對(duì)這種和契約測(cè)試綁定的集成測(cè)試的佳谦。功能測(cè)試和契約測(cè)試戴涝,是完全不同的測(cè)試活動(dòng),它們肩負(fù)各自的使命钻蔑、體現(xiàn)各自的價(jià)值啥刻,應(yīng)該各司其職。這是我和Beth Skurrie(Pact最主要的核心開(kāi)發(fā)成員咪笑,沒(méi)有之一)多次探討的一致共識(shí)可帽。
測(cè)試范疇,是另一個(gè)需要考慮的問(wèn)題窗怒。上面提到過(guò)映跟,Pact將契約測(cè)試的范疇定義在了communicate。什么是communicate呢扬虚?很簡(jiǎn)單努隙,通過(guò)通訊獲取信息。具體到契約測(cè)試中辜昵,(可)通訊荸镊,體現(xiàn)在API的endpoint接受request(request包括protocol,url路鹰,header贷洲,body等),返回response晋柱;(可)獲取信息优构,體現(xiàn)在獲取的response能夠被按照期望的方式解析(反序列化)。需要強(qiáng)調(diào)的是雁竞,communicate的內(nèi)容不應(yīng)該包含"使用信息"钦椭。使用信息拧额,是consumer的領(lǐng)域邏輯需要處理的問(wèn)題,而信息使用得是否正確彪腔,則應(yīng)該是consumer的功能測(cè)試關(guān)注的范疇侥锦。注意,這里的功能測(cè)試可以發(fā)生在單元測(cè)試德挣、組件測(cè)試恭垦、集成測(cè)試等各個(gè)測(cè)試級(jí)別。這就是為什么Pact的官方示例文檔中格嗅,在consumer端番挺,僅僅斷言了response的status code這些非常簡(jiǎn)單的數(shù)據(jù)。如果consumer團(tuán)隊(duì)確實(shí)有需求屯掖,跨出communicate的范疇來(lái)構(gòu)建集成測(cè)試玄柏,那么請(qǐng)一定合理斟酌你們的測(cè)試范疇。
"生產(chǎn)者驅(qū)動(dòng)的契約測(cè)試"贴铜?
相較于到目前為止通篇強(qiáng)調(diào)的"消費(fèi)者驅(qū)動(dòng)的契約測(cè)試"粪摘,你可能在其他地方,或多或少的绍坝,看到過(guò)"生產(chǎn)者驅(qū)動(dòng)的契約測(cè)試"的命題徘意。
單論契約
,確實(shí)可以分為"消費(fèi)者驅(qū)動(dòng)的契約"和"生產(chǎn)者驅(qū)動(dòng)的契約"轩褐,但述及契約測(cè)試
映砖,到目前為止,恕俺視野有限灾挨,我并不認(rèn)為"生產(chǎn)者驅(qū)動(dòng)的契約測(cè)試"是一種正確的表述。
契約
不等于契約測(cè)試
竹宋,這不必贅述劳澄;無(wú)論是消費(fèi)者驅(qū)動(dòng)、還是生產(chǎn)者驅(qū)動(dòng)蜈七,其實(shí)質(zhì)一定都必須是契約測(cè)試秒拔。這點(diǎn),消費(fèi)者驅(qū)動(dòng)的契約測(cè)試不必多說(shuō)飒硅,但對(duì)于"生產(chǎn)者驅(qū)動(dòng)的契約測(cè)試"砂缩,事實(shí)可能并不是這樣。生產(chǎn)者驅(qū)動(dòng)的契約測(cè)試三娩,其實(shí)質(zhì)庵芭,就是上面討論過(guò)的
基于契約的測(cè)試(契約驅(qū)動(dòng)的測(cè)試)
;具體來(lái)說(shuō)雀监,生產(chǎn)者驅(qū)動(dòng)的契約測(cè)試双吆,強(qiáng)調(diào)的是眨唬,當(dāng)provider有需求和計(jì)劃更新既有服務(wù)的schema時(shí),在實(shí)際部署變更之前好乐,先更新相應(yīng)的"契約"(為什么這里的契約要加引號(hào)匾竿,自己琢磨琢磨),新的"契約"蔚万,如果包含契約破壞岭妖,會(huì)導(dǎo)致consumer端的(契約驅(qū)動(dòng)的集成)測(cè)試掛掉。由此反璃,consumer端可以在provider端真正部署包含契約破壞的服務(wù)之前昵慌,獲得預(yù)警,從而對(duì)consumer做必要的更新準(zhǔn)備版扩,來(lái)適配provider將會(huì)部署上線的更新內(nèi)容废离;
在我看來(lái),這是契約測(cè)試的一種反模式礁芦。在消費(fèi)者驅(qū)動(dòng)的契約測(cè)試中蜻韭,契約是復(fù)數(shù)存在的,每一份契約都會(huì)被provider測(cè)試柿扣,如果有契約破壞肖方,會(huì)被及時(shí)反饋,必要的時(shí)候會(huì)被修正未状;而"生產(chǎn)者驅(qū)動(dòng)的契約測(cè)試"中俯画,"契約"是唯一存在的,它的正確性是不會(huì)被測(cè)試和質(zhì)疑的司草,它僅僅會(huì)被consumer用來(lái)驗(yàn)證自己能否正確消費(fèi)這份"契約"艰垂,所以,"生產(chǎn)者驅(qū)動(dòng)的契約測(cè)試"埋虹,測(cè)試的并不是"契約"猜憎,而是consumer。
“如果質(zhì)疑生產(chǎn)者驅(qū)動(dòng)的契約測(cè)試搔课,是因?yàn)樗鼫y(cè)試的不是契約胰柑,而是consumer,那么是否也可以質(zhì)疑消費(fèi)者驅(qū)動(dòng)的契約測(cè)試爬泥,測(cè)試的也不是契約柬讨,而是provider呢?” 形式上來(lái)看袍啡,好像確實(shí)如此踩官。但如果我們進(jìn)一步分析,不難發(fā)現(xiàn)境输,消費(fèi)者驅(qū)動(dòng)的契約測(cè)試卖鲤,對(duì)于不可接受的契約破壞的最終結(jié)果肾扰,要么是provider自主的功能修改被駁回,要么就是consumer主張的契約變更被駁回蛋逾。結(jié)論就是集晚,消費(fèi)者驅(qū)動(dòng)的契約測(cè)試,是對(duì)契約的雙方進(jìn)行約束区匣,這體現(xiàn)了契約的意義偷拔,另一方面,對(duì)于不可接受的契約破壞亏钩,無(wú)論是哪一方引入的莲绰,它都將會(huì)被駁回,這體現(xiàn)了測(cè)試的意義(任何“功能”姑丑,如果交付測(cè)試后蛤签,無(wú)論結(jié)果好壞,它都是不可逆的栅哀,那測(cè)試本身也就失去了意義)震肮。再來(lái)看“生產(chǎn)者驅(qū)動(dòng)的契約測(cè)試”,一旦provider發(fā)布了“契約”留拾,無(wú)論是否發(fā)生(對(duì)任一consumer)不可接受的契約破壞戳晌,無(wú)論“測(cè)試”的結(jié)果如何,這份“契約”都不可能被駁回痴柔,這樣的“測(cè)試”沦偎,如果還說(shuō)它的測(cè)試對(duì)象是“契約”的話,那這種“測(cè)試”對(duì)契約來(lái)說(shuō)是沒(méi)有意義的咳蔚。歸根到底豪嚎,還是"契約測(cè)試"和"基于契約的測(cè)試(契約驅(qū)動(dòng)的測(cè)試)"的區(qū)別。
當(dāng)然谈火,這樣的測(cè)試活動(dòng)疙渣,并不是一無(wú)是處,在一些上下游非常不穩(wěn)定的微服務(wù)集群中堆巧,特別是在一些服務(wù)集群跨部門,甚至跨公司的多團(tuán)隊(duì)合作項(xiàng)目中泼菌,由于缺乏及時(shí)有效的溝通谍肤,往往更容易造成這樣那樣的契約破壞,此時(shí)哗伯,這種基于契約的測(cè)試活動(dòng)荒揣,能很好的預(yù)警provider的API schema變更對(duì)consumer的影響,這是非常有意義的焊刹。
最后
關(guān)于契約測(cè)試本身系任,和契約測(cè)試實(shí)施的問(wèn)題恳蹲,我想,遠(yuǎn)不止上面訴及的方面俩滥。不同的人嘉蕾、不同的團(tuán)隊(duì),對(duì)契約測(cè)試的理解也可能都不一樣霜旧,特別是错忱,當(dāng)一種(比較)新的理念在不同的現(xiàn)實(shí)項(xiàng)目中付諸實(shí)踐時(shí),可能遇到的問(wèn)題挂据,和思考的方式又會(huì)有所迥異以清,這些都是我們理解一種理念的正常途徑。
問(wèn)題永遠(yuǎn)都是客觀存在的崎逃,但解題的思路卻可以千奇百怪掷倔。我們討論P(yáng)act、Swagger和Spring Cloud Contract个绍,我們辯駁消費(fèi)者驅(qū)動(dòng)和生產(chǎn)者驅(qū)動(dòng)勒葱,我們思考是先寫(xiě)契約測(cè)試還是先寫(xiě)功能測(cè)試,這些思想的碰撞越多障贸,越能幫助我們?nèi)ニ伎即砩⒗斫夂涂偨Y(jié),繼而產(chǎn)生出更加富有想象力的答案篮洁。比如涩维,當(dāng)需要把provider的schema中的一個(gè)String改成Object,從契約的角度袁波,我們還在糾結(jié)如何協(xié)調(diào)所有的consumer影響最小時(shí)瓦阐,“聰明”的小伙伴已經(jīng)給出了這樣一個(gè)答案:不把String改成Object,而是直接添加這個(gè)Object
篷牌。
最后睡蟋,送上我經(jīng)常講的一個(gè)問(wèn)題:你知道最簡(jiǎn)單靠譜的契約測(cè)試工具是什么嗎?是郵箱枷颊!╮( ̄▽ ̄)╭