能力、能力压鉴、能力崖咨。重要的事情一定要說三遍!
既然已經(jīng)有那么多書告訴我們敏捷測(cè)試應(yīng)該怎么做油吭,那為什么還有那么多團(tuán)隊(duì)(我看到的至少一半以上轉(zhuǎn)型到敏捷開發(fā)模式的團(tuán)隊(duì))無法做好測(cè)試呢击蹲?或者說并沒有感受到測(cè)試效果有明顯的提升?
答案只可能有一個(gè)——我們雖然知道該怎么做婉宰,但我們并沒有做到位歌豺,準(zhǔn)確的說是我們?nèi)鄙僮龅轿坏哪芰Γ∥抑滥憧吹竭@里時(shí)內(nèi)心深處是不屑的心包,心里一定在想自己的能力肯定是OK的类咧,問題就在這,我們?nèi)鄙僮龅轿坏哪芰π诽冢瑫r(shí)我們不承認(rèn)這一點(diǎn)所以我們又進(jìn)一步失去了提升能力的可能痕惋。
我們可以嘗試從不同類型測(cè)試的角度稍作回顧。
單元測(cè)試
內(nèi)心其實(shí)是拒絕的
即使團(tuán)隊(duì)做了敏捷轉(zhuǎn)型娃殖,還是有很多開發(fā)人員拒絕寫單元測(cè)試值戳,原因無非有下面幾種:
難寫難調(diào),耗時(shí)太長(zhǎng)炉爆,寫業(yè)務(wù)代碼就半天時(shí)間堕虹,寫單元測(cè)試可能要兩天
方案稍做修改,單元測(cè)試就廢了芬首,需要重新寫一遍
當(dāng)然還有一部分開發(fā)人員純粹就是不想做“多余的事”鲫凶,只要我交付了功能,你管我寫單元測(cè)試沒有衩辟,寫代碼對(duì)這部分開發(fā)人員來說可能只是混口飯吃而已螟炫,人各有志,這里就不討論了艺晴。
不管什么單元測(cè)試框架通常會(huì)有一定的學(xué)習(xí)成本昼钻,特對(duì)第一次接觸xUnit框架時(shí)需要花一段時(shí)間才能適應(yīng)一些奇怪的語法。剛剛接觸單元測(cè)試的開發(fā)人員有很多會(huì)認(rèn)為效率低封寞,成本太高然评,這其實(shí)是一個(gè)很大的誤解,認(rèn)為開發(fā)人員的工作就是產(chǎn)出代碼狈究,而準(zhǔn)確的說法是交付可供用戶使用的功能碗淌,在這個(gè)過程中代碼編寫所占的工作量只是很小的部分,還包括用戶需求溝通和理解,如何轉(zhuǎn)換為軟件需求亿眠,方案設(shè)計(jì)碎罚,編碼,調(diào)試纳像,測(cè)試荆烈,驗(yàn)收,最終交付竟趾,在編碼環(huán)境為了提升效率而舍棄單元測(cè)試憔购,就好比上山砍柴卻不想磨刀,在這個(gè)環(huán)節(jié)節(jié)省的時(shí)間將來會(huì)在調(diào)試岔帽,測(cè)試玫鸟,驗(yàn)收甚至是交付之后加倍的浪費(fèi)出去。如果我們觀察一個(gè)項(xiàng)目里面要求開發(fā)人員提供每日聯(lián)調(diào)報(bào)告的話犀勒,那基本可以斷定這個(gè)項(xiàng)目在單元測(cè)試這個(gè)環(huán)節(jié)偷懶了鞋邑,因?yàn)榫邆涑浞謫卧獪y(cè)試的代碼,在聯(lián)調(diào)階段的效率是非常高的账蓉。
對(duì)于第二種,其實(shí)反映的是代碼接口設(shè)計(jì)的不合理逾一,也可能是邏輯分層有問題铸本,也可能是耦合太緊,開發(fā)人員發(fā)現(xiàn)在這種問題其實(shí)是回顧和提升自身設(shè)計(jì)能力的好機(jī)會(huì)遵堵,一旦我們停止抱怨箱玷,以積極的態(tài)度來面對(duì),認(rèn)真分析找到根因所在陌宿,反復(fù)去打磨我們的代碼锡足,就能夠脫胎換骨,破繭而出壳坪!
寫不出好的單元測(cè)試
說到單元測(cè)試不得不說說TDD舶得,我個(gè)人評(píng)價(jià)單元測(cè)試好壞的標(biāo)準(zhǔn)是
優(yōu)秀的單元測(cè)試 = 以TDD的方式寫出來的單元測(cè)試
這句話這么說也成立:
先寫代碼后補(bǔ)單元測(cè)試 = 一般的單元測(cè)試
很多開發(fā)人員度過了第一關(guān),在代碼開發(fā)完成之后開始嘗試編寫一些單元測(cè)試爽蝴,但是絕大多數(shù)會(huì)止步于TDD沐批,原因還是一樣的,成本太高……
如果你有過先寫代碼后寫UT的經(jīng)驗(yàn)蝎亚,下面這幾種情形多少會(huì)經(jīng)歷過:
測(cè)試的有效性很難保證九孩,有時(shí)候代碼有bug,跟著編寫單元測(cè)試的時(shí)候?qū)懯清e(cuò)的发框,等到后面聯(lián)調(diào)或者集成測(cè)試才發(fā)現(xiàn)
用例很長(zhǎng)躺彬,寫100行的業(yè)務(wù)代碼,對(duì)應(yīng)要寫上500行的單元測(cè)試代碼,而且總感覺還有什么場(chǎng)景沒有考慮到
當(dāng)行覆蓋率達(dá)到85%以上之后宪拥,再想往上提升就變得異常困難
用例調(diào)試起來困難仿野,細(xì)節(jié)很多,一旦用例失敗江解,可能需要花很長(zhǎng)時(shí)間才能修復(fù)
看半個(gè)月之前寫的用例设预,已經(jīng)完全不知道寫的是啥
在網(wǎng)上經(jīng)常看到開發(fā)人員對(duì)代碼編輯工具好壞的討論犁河,Vim黨在這個(gè)話題上表現(xiàn)非潮钫恚活躍,據(jù)說只要堅(jiān)持幾周使用Vim你就會(huì)對(duì)所有其他工具嗤之以鼻桨螺,然而真正能堅(jiān)持下來的不多宾符,TDD大概也是一樣,等你真正掌握TDD的技巧之后灭翔,如果你不用TDD的方式開發(fā)反而會(huì)覺得各種別扭魏烫,可惜的是能再往前邁出一步,看到這種風(fēng)景的開發(fā)人員是少之又少肝箱,以個(gè)人經(jīng)驗(yàn)來看哄褒,這個(gè)比例大概只有5%!
什么叫好的單元測(cè)試
說到這個(gè)話題煌张,首先要排除的一種是沒有ASSERT的測(cè)試用例呐赡,這種用例很容易編寫,也能達(dá)到很高的行覆蓋率骏融,然而完全沒有任何價(jià)值链嘀,會(huì)編寫這種用例的開發(fā)人員最好是早點(diǎn)識(shí)別出來并請(qǐng)出團(tuán)隊(duì)(如果你能做到的話)。
對(duì)于面向?qū)ο蟮恼Z言档玻,單元測(cè)試的測(cè)試對(duì)象就是一個(gè)具體的實(shí)現(xiàn)類怀泊,在TDD時(shí)我們先設(shè)計(jì)一個(gè)最正常的流程用例,并編寫代碼使用例通過误趴,然后再識(shí)別這個(gè)用例中所有正交的外部依賴(比如入?yún)⑴怼⒁蕾嚨耐獠拷涌冢缓笠缘谝粋€(gè)用例為基準(zhǔn)每次變化一個(gè)維度來進(jìn)行用例設(shè)計(jì)凉当。
比如測(cè)試對(duì)象類A依賴3個(gè)接口分別為iB碧囊,iC ,iD纤怒,每個(gè)接口再調(diào)用時(shí)分別有 2種糯而,2種,3種返回值泊窘,那么雖然總共的業(yè)務(wù)分支有 223=12 種熄驼,但實(shí)際上以正交方式來設(shè)計(jì)用例時(shí)我們只需要 2+2+3-2 = 5個(gè)像寒,即足以驅(qū)動(dòng)我們編寫出所有分支的代碼了!以一個(gè)表格的方式來表示:
iB | iC | iD |
---|---|---|
1 | 1 | 1 |
2 | 1 | 1 |
1 | 2 | 1 |
1 | 1 | 2 |
1 | 1 | 3 |
如果你不用TDD而是采用后補(bǔ)的方式來設(shè)計(jì)用例瓜贾,則很難體會(huì)到這種正交設(shè)計(jì)所帶來的安全感诺祸,即使你把12種業(yè)務(wù)分支全部組合測(cè)試一遍,很可能還是會(huì)擔(dān)心漏掉了什么場(chǎng)景祭芦,而且這些用例看起來也無法體現(xiàn)思路的連續(xù)性筷笨,起可讀性也不高。而且龟劲,如果你不曾體會(huì)到TDD的3步軍規(guī)“編寫一個(gè)失敗的用例”-》“編寫代碼讓這個(gè)用例通過”-》“重構(gòu)”胃夏,就很難理解為什么只需要5個(gè)用例就能覆蓋所有的場(chǎng)景了,因?yàn)槟阍黾映@5個(gè)用例之外的其他用例昌跌,你會(huì)發(fā)現(xiàn)直接就運(yùn)行通過了仰禀,按照TDD的看法,這種用例沒有存在的價(jià)值蚕愤。
功能測(cè)試
缺少用戶思維和用戶溝通能力
一般來說功能測(cè)試框架更容易掌握一點(diǎn)答恶,比如Robot Framework這種基于關(guān)鍵字的測(cè)試框架,有一定經(jīng)驗(yàn)的開發(fā)人員只需要2-3天就能基本掌握萍诱。功能測(cè)試的難點(diǎn)在于用戶思維悬嗓,從用戶的角度出發(fā),那些場(chǎng)景是最常用的場(chǎng)景裕坊,那些場(chǎng)景是風(fēng)險(xiǎn)最大的場(chǎng)景包竹,我們需要對(duì)這些場(chǎng)景進(jìn)行功能測(cè)試用例的設(shè)計(jì)。
在設(shè)計(jì)功能測(cè)試用例時(shí)碍庵,很有可能某些測(cè)試場(chǎng)景和單元測(cè)試有一定的重復(fù),但是沒有關(guān)系悟狱,畢竟這是從兩個(gè)不同的視角來設(shè)計(jì)的用例静浴,代碼內(nèi)部設(shè)計(jì)可能將來會(huì)重構(gòu),單元測(cè)試也會(huì)相應(yīng)修改挤渐,但只要功能不變其功能測(cè)試就不用做任何修改苹享。
在實(shí)際開發(fā)功能測(cè)試用例時(shí),開發(fā)人員包括QA經(jīng)常很難從用戶角度來對(duì)功能測(cè)試用例進(jìn)行識(shí)別浴麻,原因在于開發(fā)人員看到的是由PO翻譯過來的軟件需求得问,而不是原始的用戶需求,要理解原始的用戶需求就需要開發(fā)人員和PO甚至是需求客戶深入的溝通软免,然而實(shí)際情況宫纬,我看到的大多數(shù)開發(fā)人員甚至是QA都不擅長(zhǎng)這種溝通,這導(dǎo)致在功能測(cè)試設(shè)計(jì)時(shí)就會(huì)很迷惑膏萧。
不愿意隔離外部依賴
功能測(cè)試的另一個(gè)難點(diǎn)是對(duì)外部依賴的隔離漓骚,在單元測(cè)試我們經(jīng)常使用Mock技術(shù)蝌衔,在功能測(cè)試階段則經(jīng)常使用打樁(Stub)技術(shù),比如說依賴一個(gè)外部模塊(比如需要和這個(gè)外部模塊進(jìn)行消息的交互)蝌蹂,在功能測(cè)試時(shí)噩斟,正確的做法是編寫這個(gè)外部依賴的樁實(shí)現(xiàn),在功能測(cè)試用例中通過模擬這個(gè)這個(gè)外部模塊的不同返回值來執(zhí)行不同場(chǎng)景的測(cè)試孤个。
而實(shí)際開發(fā)時(shí)剃允,大多數(shù)開發(fā)人員并不愿意開發(fā)這個(gè)樁實(shí)現(xiàn),既然需要跑一個(gè)外部依賴齐鲤,那就把真實(shí)的外部依賴跑起來唄斥废,這看起來是一個(gè)低成本的解決方案,然而我們要意識(shí)到這個(gè)外部依賴可能也還在開發(fā)中佳遂,其實(shí)現(xiàn)并不可靠营袜,甚至進(jìn)度處于落后狀態(tài),如果只有一個(gè)外部依賴的話風(fēng)險(xiǎn)可能還處于可控狀態(tài)丑罪,而真實(shí)場(chǎng)景下外部依賴可能有多個(gè)荚板,這些外部依賴中只要一個(gè)掉鏈子那功能測(cè)試就不能正常運(yùn)行。做個(gè)簡(jiǎn)單的概率計(jì)算吩屹,假設(shè)外部依賴還是3個(gè)跪另,每個(gè)外部依賴正常執(zhí)行的概率是80%(看起來還可以接受),最終測(cè)試用例能正常執(zhí)行的概率就是80%80%80%=50%煤搜。這也是我們經(jīng)趁饴蹋看到很多團(tuán)隊(duì)功能測(cè)試執(zhí)行成功率非常低的原因之一。
自動(dòng)化的泥潭
這個(gè)話題和上個(gè)話題其實(shí)是同一個(gè)擦盾,在功能測(cè)試中如果不能將外部依賴隔離開來嘲驾,我們?cè)趯?shí)施自動(dòng)化的時(shí)候就會(huì)陷入困境。
自動(dòng)化測(cè)試給我們提供了一個(gè)非常及時(shí)的反饋機(jī)制迹卢,當(dāng)我們提交新代碼之后辽故,如果 CI 變成了紅色,意味著新提交的代碼有問題腐碱,我們需要及時(shí)修復(fù)或者回退誊垢,以保證在最短的時(shí)間里將 CI 恢復(fù)。而如果在自動(dòng)化測(cè)試執(zhí)行時(shí)依賴了太多外部不穩(wěn)定的因素症见,比如說網(wǎng)絡(luò)喂走、數(shù)據(jù)庫、其他處于開發(fā)階段的組件谋作,就會(huì)帶來下面這些問題:
- 自動(dòng)化環(huán)境難以維護(hù)芋肠,搭建環(huán)境很困難,一旦環(huán)境出現(xiàn)出現(xiàn)問題要定位和修復(fù)的周期長(zhǎng)
- 自動(dòng)化測(cè)試運(yùn)行速度慢遵蚜,比如需要半天才能執(zhí)行一次业栅,上午提交的代碼可能需要等到下班才能看到影響
- 自動(dòng)化測(cè)試執(zhí)行通過率低秒咐,這個(gè)原因在上面已經(jīng)說明,CI 長(zhǎng)期處于紅色會(huì)讓開發(fā)人員無法得到及時(shí)反饋碘裕,喪失 CI 的價(jià)值
- 各組件團(tuán)隊(duì)之間互相扯皮携取,推諉責(zé)任,助長(zhǎng)不好的開發(fā)文化形成
探索性測(cè)試
測(cè)試的直覺
探索性測(cè)試的能力的高低基本可以區(qū)分一個(gè)QA到底是優(yōu)秀還是普通帮孔,因?yàn)樘剿餍詼y(cè)試有點(diǎn)類似武俠小說中的“無招勝有招”雷滋,在單元測(cè)試中,我們可以識(shí)別測(cè)試對(duì)象的外部依賴并對(duì)其進(jìn)行正交設(shè)計(jì)文兢,在功能測(cè)試中只要我們能和用戶建立有效的溝通晤斩,將用戶需求理解透徹,要梳理出測(cè)試重點(diǎn)和風(fēng)險(xiǎn)也不難姆坚,但是在探索性測(cè)試中澳泵,更加強(qiáng)調(diào)測(cè)試人員的直覺(個(gè)人更喜歡靈性這個(gè)詞)。
直覺不是憑空出現(xiàn)的兼呵,需要通過大量甚至反復(fù)的練習(xí)來積累兔辅,是建立在對(duì)系統(tǒng)非常深入的了解之上。打個(gè)比方击喂,在警察系統(tǒng)中维苔,優(yōu)秀的探員能敏銳的抓住在其他探員眼中非常不起眼的線索并破解案件,如果問這位優(yōu)秀的探員為什么是他而不是其他人注意到這條線索懂昂,他往往自己也不清楚介时,只能說“我就是知道”。
在進(jìn)行探索性測(cè)試時(shí)凌彬,我們選擇某一個(gè)“感覺有問題”的點(diǎn)沸柔,選擇不同的輸入來進(jìn)行測(cè)試,在測(cè)試的同時(shí)仔細(xì)觀察系統(tǒng)的反應(yīng)铲敛,不遺巨細(xì)褐澎,認(rèn)真思考,并根據(jù)結(jié)果和我們的經(jīng)驗(yàn)來調(diào)整下一步的測(cè)試動(dòng)作原探,或選用更合適的工具乱凿,或找開發(fā)人員就某個(gè)不確切的細(xì)節(jié)進(jìn)行討論顽素,一次卓有成效的探索性測(cè)試應(yīng)該能讓測(cè)試人員進(jìn)入“心流”的狀態(tài)咽弦,在測(cè)試完成之后收獲滿滿的成就感。
如果我們回到瀑布式開發(fā)的年代胁出,在版本發(fā)布前的一兩周我們會(huì)集中力量來進(jìn)行測(cè)試型型,而且經(jīng)常是人肉測(cè)試,其實(shí)就有很多次全蝶,我們也曾經(jīng)沒有意識(shí)的進(jìn)入了這種“心流”的狀態(tài)闹蒜,只是我們不知道我們正在執(zhí)行探索性測(cè)試寺枉。
自動(dòng)化的神話
傳統(tǒng)團(tuán)隊(duì)轉(zhuǎn)型敏捷后,第一步要做的事情就是測(cè)試自動(dòng)化和持續(xù)集成绷落,在一個(gè)從沒做過自動(dòng)化測(cè)試的團(tuán)隊(duì)中引入這項(xiàng)實(shí)踐會(huì)給所有人包括項(xiàng)目經(jīng)理帶來顯而易見的收獲以及心靈上巨大的震撼姥闪。
很多團(tuán)隊(duì)和項(xiàng)目都會(huì)度量測(cè)試用例的自動(dòng)化比例來衡量當(dāng)前測(cè)試工作的狀態(tài),追求100%的測(cè)試自動(dòng)化砌烁。這個(gè)指標(biāo)沒錯(cuò)筐喳,我們應(yīng)該自動(dòng)化所有能自動(dòng)化的測(cè)試用例,問題在于自動(dòng)化測(cè)試同樣不是銀彈函喉,如果在我們的組織中過度強(qiáng)調(diào)自動(dòng)化的重要性避归,就會(huì)帶來一個(gè)錯(cuò)覺——所有手工的測(cè)試都是錯(cuò)誤的!這種錯(cuò)覺一旦形成管呵,探索性測(cè)試就會(huì)消失梳毙,至少在這個(gè)領(lǐng)域我們反而會(huì)沒有瀑布式開發(fā)做的更好。
當(dāng)我們看到團(tuán)隊(duì)已經(jīng)具備了上千的自動(dòng)化用例捐下,但還是在演示會(huì)或者系統(tǒng)測(cè)試環(huán)節(jié)账锹,甚至是隨手一點(diǎn)的時(shí)候出現(xiàn)了我們預(yù)期之外的結(jié)果,那就要小心我們是不是在探索性測(cè)試上疏忽了……
壓力測(cè)試
壓力測(cè)試或者性能測(cè)試的重要性不言而喻蔑担,不管是瀑布式的還是敏捷的牌废,壓力測(cè)試相信沒有誰敢跳過,但壓力測(cè)試的環(huán)境搭建起來比較麻煩啤握,執(zhí)行一次所需要的時(shí)間也比較長(zhǎng)鸟缕,所以一般來說執(zhí)行的頻率不會(huì)太高,如果能做到一周執(zhí)行一次已經(jīng)相當(dāng)高了排抬,壓力測(cè)試給出的結(jié)論通常就是簡(jiǎn)單的通過or不通過懂从,只有在不通過的時(shí)候,開發(fā)人員才會(huì)進(jìn)一步通過log或者運(yùn)用profile工具來進(jìn)行蹲蒲,找出瓶頸并解決番甩。
這里有個(gè)小小的問題是,當(dāng)我們執(zhí)行一次壓力測(cè)試發(fā)現(xiàn)了部分問題后届搁,開發(fā)人員直接修復(fù)了這些問題缘薛,等到下一次壓力測(cè)試的時(shí)候,我們又可能發(fā)現(xiàn)類似的地方再次出現(xiàn)了性能瓶頸卡睦。也就是說壓力測(cè)試不能做到如單元測(cè)試或者自動(dòng)化功能測(cè)試那樣頻繁的反饋宴胧。
解決的辦法也很簡(jiǎn)單,當(dāng)我們分析出某段代碼可能存在性能瓶頸之后表锻,我們除了修復(fù)代碼之外恕齐,還可以進(jìn)一步針對(duì)這部分代碼編寫自動(dòng)化的單元測(cè)試或者功能測(cè)試用例,這里需要一些技巧瞬逊,當(dāng)并不是很困難显歧,這樣做的好處是利用單元測(cè)試和功能測(cè)試的快速反饋的效果仪或,來對(duì)壓力測(cè)試已經(jīng)發(fā)現(xiàn)的問題進(jìn)行防護(hù)。
遺憾的是就是這么簡(jiǎn)單的一步士骤,很多團(tuán)隊(duì)又止步于此了范删。
小結(jié)
敏捷軟件測(cè)試的四象限分類方式已經(jīng)廣為人知,但遺憾的是大多數(shù)團(tuán)隊(duì)缺乏對(duì)其深入理解缺的能力拷肌,也缺乏主動(dòng)提升能力的欲望瓶逃,一旦碰到超過我們現(xiàn)有能力范圍之外的時(shí)候我們往往就發(fā)揮了中國人的“聰明”,轉(zhuǎn)而去采取某種簡(jiǎn)單or變通的方式廓块,而且說服自己和周圍的人相信這是某種提升厢绝,然而聰明反被聰明誤,可惜……