我于2001年以工程總監(jiān)的身份加入Google。當時,Google大概有200名開發(fā)人員,但只有區(qū)區(qū)3位測試人員!那個時候,開發(fā)人員已經(jīng)開始做自己代碼的測試了,但由于測試驅(qū)動開發(fā)的模式才剛剛開始,而且像JUnit這樣的測試框架也沒有大規(guī)模使用。當時的測試主要是在做一些隨機測試(ad-hoc testing),其好壞取決于編寫代碼的開發(fā)者的責任心。但即使那樣也是可以接受的,因為,當時正處在創(chuàng)業(yè)階段,必須快速前進并勇于冒險,否則就無法和那個時代已經(jīng)非常強大的對手競爭。
然而,當Google逐漸成長變大,Google的一些產(chǎn)品對于最終用戶和客戶來說開始變得至關(guān)重要(例如,競價廣告產(chǎn)品,我曾經(jīng)負責的產(chǎn)品,很快變成許多網(wǎng)站的主要收入來源),我們清晰地認識到必須加大對測試的關(guān)注和投入。但只有3個測試工程師,別無選擇,只能讓開發(fā)來做更多的測試。與其他的幾個Googler(譯注:Google員工,本書中一般指Google工程師)一起,我們介紹、培訓、推行單元測試,我們鼓勵開發(fā)人員把測試作為優(yōu)先級較高的事去做,并建議使用一些工具,如JUnit,把測試做成自動化的。但是進展緩慢.
開發(fā)人員發(fā)現(xiàn),為了測試充分,他們不得不針對每一行功能代碼,寫兩到三行的單元測試代碼,而且這些測試代碼和功能代碼一樣都需要維護,且有著相同的出錯概率。而且大家也意識到,僅做單元測試是不夠的,仍然需要集成測試、系統(tǒng)測試、用戶界面等方面的測試。當真正開始要去做測試的時候,會發(fā)現(xiàn)測試工作量變得非常大(且需要很多知識的學習),并要求在很短的時間內(nèi)完成測試,要以"迅雷不及掩耳"之勢完成。
我們?yōu)槭裁匆诤芏痰臅r間內(nèi)迅速地完成測試呢? 我一直這么認為,對于一個壞點子或考慮欠周的產(chǎn)品,即便再多的測試,也無法把它變成一個成功的產(chǎn)品。但如果測試方法不當,卻會扼殺一個本來有機會成功的產(chǎn)品或公司,至少會拖慢這個產(chǎn)品的速度,讓競爭對手有機可乘。
- Patrick Copeland 谷歌測試和部署技術(shù)的架構(gòu)師
我在Google的旅程始于2005年3月。Alberto在前面的序中也介紹了一些當時Google的狀況:雖然公司規(guī)模還比較小,但已開始感受到成長帶來的煩惱。當時適逢快速的技術(shù)變革之際,Web世界正在迎接動態(tài)內(nèi)容的到來,而云計算也正在逐漸成為一種新的選擇,取代當時還占統(tǒng)治地位的客戶機-服務(wù)器架構(gòu)
我加入Google的時候,工程團隊還不足1000人。測試團隊大概有50名全職人員和一些臨時工,具體數(shù)量我一直沒搞清楚。測試團隊當時的稱謂是"測試服務(wù)",工作重點在UI的驗證上,隨時響應(yīng)不同項目的測試需求??梢韵胂?,這并不是Google最閃耀的團隊。
但這在當時已經(jīng)足夠了。Google當時的主要業(yè)務(wù)是搜索和廣告,規(guī)模要比今天小得多,一次徹底的探索式測試足以發(fā)現(xiàn)絕大多數(shù)的質(zhì)量問題。然而,世界在變,Web點擊量開始史無前例地爆發(fā)性增長,文檔化的Web正在讓位于應(yīng)用化的Web。你可以感覺到勢不可擋的成長和變化,在這種情況下,規(guī)?;涂焖龠M入市場的能力變得至關(guān)重要和生死攸關(guān)。
在Google內(nèi)部,規(guī)模和問題的復(fù)雜性給測試服務(wù)團隊帶來了巨大的壓力。在之前小型的、類同的項目里的一些可行做法,現(xiàn)在卻讓優(yōu)秀的測試人員感到筋疲力盡,疲于奔命在多個急需救火的項目之間。更加火上澆油的是,Google在項目快速發(fā)布方面的堅持。是時候采取措施了,我面臨兩個選擇,要么沿用這種勞動密集型的流程增加更多的人手,要么改變整個游戲規(guī)則。為了適應(yīng)業(yè)界和Google發(fā)生的巨變,測試服務(wù)團隊需要根本性的變革。
我也很想說自己是借助于豐富的經(jīng)驗構(gòu)思出了完美的測試組織模型,但實事求是地講,我從過去的經(jīng)歷中,學到的只不過是一些過時的做法。我所工作或領(lǐng)導過的每個測試組織都有這樣或那樣的問題。有問題是常態(tài),代碼質(zhì)量很糟糕,測試用例很差勁,團隊也問題多多。我完全清楚那種被技術(shù)質(zhì)量債壓得喘不過氣來的感受,在那種狀態(tài)下,一切創(chuàng)新性的想法都會被遏制,以免不小心破壞了脆弱的產(chǎn)品。如果說我在以往的經(jīng)歷中有所收獲的話,那就是經(jīng)歷了各種錯誤的測試實踐。
那個時候,以我對Google的了解,有一件事情是確定無疑的,那就是Google對于計算機科學和編程能力非常重視。從根本上說,如果測試人員想加入這個俱樂部,就必須具備良好的計算機科學基礎(chǔ)和編程能力。
變革Google測試的首要問題是重新定位身為測試人員的意義所在。我過去經(jīng)常在頭腦中想象理想團隊的模型,想象這樣的團隊是如何肩負起質(zhì)量重任的,每次我都會得到相同的結(jié)論:一個團隊能編寫出高質(zhì)量軟件的唯一途徑是全體成員共同對質(zhì)量負責,包括產(chǎn)品經(jīng)理、開發(fā)人員、測試人員等所有人。我認為,達到此目標的最好方式是使測試人員有能力將測試變成代碼庫的一個實際功能,而測試功能的地位應(yīng)該與真實客戶看到的任何其他功能同等重要。我所需要的能夠?qū)崿F(xiàn)測試功能的技能,也正是開發(fā)人員需要具備的技能。
招聘具備開發(fā)能力的測試人員很難,找到懂測試的開發(fā)人員就更難,但是維持現(xiàn)狀更要命,我只能往前走。我希望測試人員能為他們的產(chǎn)品做更多的事情,同時,我希望演變測試工作的性質(zhì)和從屬,要求開發(fā)團隊更大地投入。這種組織結(jié)構(gòu)在當時的業(yè)界尚未實現(xiàn),但我堅信它非常適合Google,我相信在這家公司,時機到了。
不幸的是,這種如此深刻、根本性的變革在公司里極度缺乏認同,極少有人能分享我的激情。當我開始推銷這種關(guān)于軟件測試角色的地位平等而作用不同的愿景時,我發(fā)現(xiàn)竟然難以找到一個人一起共享午餐!開發(fā)工程師們好像被他們將要在測試上發(fā)揮更大的作用這個想法嚇著了,他們指出"這是測試人員的職責"。而測試人員也不買賬,因為很多人已經(jīng)習慣了當前的角色,維持現(xiàn)狀的慣性導致任何變革都變得非常困難。
我毫不松懈地繼續(xù)努力著,主要是出于對Google的研發(fā)過程深陷技術(shù)和質(zhì)量債的困境的恐懼,一旦如此,長達5年的開發(fā)周期又會成為現(xiàn)實,而我本來已經(jīng)很高興地把它們留在客戶機-服務(wù)器的世界里了。Google是一家由天才組成的公司,以創(chuàng)新為靈魂,這種企業(yè)文化與冗長的開發(fā)周期是不相容的。這是一場值得打的戰(zhàn)斗,我說服自己,一旦這些天才理解了這種旨在打造一個生產(chǎn)線式的、可重復(fù)的"技術(shù)工廠"的開發(fā)和測試實踐 ,他們就會改變看法。他們就會理解我們不再是一個初創(chuàng)公司,快速成長的用戶群、不斷累積的bug和糟糕結(jié)構(gòu)的代碼形成的技術(shù)債將會導致開發(fā)過程的崩潰。
我逐個接觸各產(chǎn)品團隊,尋找優(yōu)秀的案例,試圖為我的立論找到比較容易的切入點。在開發(fā)人員面前,我描繪了一個持續(xù)構(gòu)建、快速部署的藍圖,一個行動敏捷、省下更多時間用于創(chuàng)新的開發(fā)過程;在測試人員面前,我激發(fā)他們對于成為同等技能、同等貢獻和同等薪酬的完全的工程合作伙伴的渴望。
開發(fā)人員的態(tài)度是,如果我們招聘到有能力做功能開發(fā)的人,那么,我們應(yīng)當讓他們做功能開發(fā)。其中一些人對我的想法非常反感,甚至發(fā)信給我的主管,非常直率地建議如何來處理我的瘋狂之舉,這些信塞滿了我的主管的郵箱。幸運的是,我的主管并沒有采納那些建議。
令我吃驚的是,測試人員的反應(yīng)竟然與開發(fā)人員類似。他們沉湎于老的做事方式,抱怨自己在開發(fā)面前的地位,但又不想去改變。
我的主管對這些抱怨只有一句話:"這里是Google,如果你有想法,盡管去做就是。"
于是我開始付諸行動。我召集了一批志同道合的骨干分子,組成了一個面試團隊,開始招聘。事情進行得比較艱難,我們尋找的人要兼具開發(fā)人員的技能和測試人員的思維,他們必須會編程,能實現(xiàn)工具、平臺和測試自動化。我們必須對招聘和面試的標準與流程做出一些調(diào)整,并向已經(jīng)習慣了既有模式的招聘委員會做出合理解釋。
最初的幾個季度進行得異常艱難。好的候選人經(jīng)常在面試過程中失利,也許是因為他們沒能很快地解決一些奇怪的編程問題,或是在某些人認為很重要的方面表現(xiàn)得不夠好(然而這些方面其實與測試技能毫不相干)。我預(yù)料到了招聘過程的困難,每周都要抽出大量時間寫辯詞。這些辯詞最終會到達Google聯(lián)合創(chuàng)始人Larry Page手里(他一直是招聘的最終批準者)。他批準了足夠多的候選人,我的團隊開始穩(wěn)步增長。直到現(xiàn)在,我猜每次Larry聽到我的名字時想到的一定是:"招聘測試的!"
當然,到這個時候,我已經(jīng)做了大量的宣傳和鼓動工作,來說服大家這是唯一的選擇。整個公司都在看著我們,一旦失敗,后果將是災(zāi)難性的。對于一個混合了很多不斷變化的外包人員和臨時人員的小測試團隊而言,期望顯得如此之高。然而,即使是在我們艱難的招聘進行中同時減少了臨時人員的數(shù)量時,我已經(jīng)注意到了變化在發(fā)生。測試資源越稀缺,給開發(fā)人員留下的測試工作就越多。很多團隊都勇敢地接受了挑戰(zhàn)。我感覺,如果技術(shù)保持不變的話,這個時候的狀態(tài)已經(jīng)在接近我們的目標了。
然而,技術(shù)不是靜止不動的,開發(fā)和測試實踐處于飛速的變化之中。靜態(tài)Web應(yīng)用的時代已經(jīng)成為過去,瀏覽器還在努力追趕之中,圍繞瀏覽器的自動化技術(shù)比已經(jīng)遲緩的瀏覽器還要落后一年。開發(fā)人員正面臨著巨大的技術(shù)變革,在這個時候,把測試交給開發(fā)人員,這看上去是徒勞的。我們甚至還不太會手工測試這些應(yīng)用,更不用提自動化測試了。
開發(fā)團隊身上的壓力也同樣巨大。當時Google 開始收購擁有富含動態(tài)Web應(yīng)用的公司。YouTube、Google Docs等后繼產(chǎn)品的融入,延展了我們內(nèi)部的基礎(chǔ)設(shè)施。開發(fā)團隊在編寫功能代碼的過程中,要面臨很多問題,與我們測試人員在測試過程中要面臨的問題一樣,令人生畏!測試人員面對的測試問題無法孤立地解決。把測試和開發(fā)割裂開來,看成兩個單獨的環(huán)節(jié),甚至是兩類截然不同的問題,這種做法是錯誤的,沿著這條路走下去意味著什么問題也解決不了。解決測試團隊的問題,只是我們前進路上的其中一步而已。
進展在繼續(xù)。雇傭優(yōu)秀的人是一件很有意思的事情,他們會推動進展的發(fā)生!到了2007年,測試團隊有了更好的定位。我們能夠很好地處理發(fā)布周期的最后環(huán)節(jié)。開發(fā)團隊已經(jīng)視我們?yōu)轫樌暇€的可靠合作伙伴。不過我們?nèi)匀皇窃诎l(fā)布過程的后期才介入的支持團隊,局限于傳統(tǒng)QA模型。盡管有了優(yōu)秀的執(zhí)行能力,我們還沒達到我設(shè)想的目標。我解決了招聘方面的問題,測試也向著正確的方向發(fā)展,但是我們還是在整個流程中介入太晚。
我們在一個被稱作"測試認證"(本書后面的章節(jié)會詳細介紹)的事情上取得了不少進展。我們向開發(fā)團隊提供咨詢,幫助他們改善代碼質(zhì)量并盡早進行單元測試。我們開發(fā)工具并指導團隊進行持續(xù)集成,使產(chǎn)品一直保持可測試的狀態(tài)。我們進行了無數(shù)的改進和調(diào)整,從而消除了之前的很多質(zhì)疑,本書詳細介紹了其中的很多方法。但是,在那個時候,還是感覺缺乏整體感,開發(fā)依舊是開發(fā),測試依舊是測試。雖然很多文化變革的因素已經(jīng)存在,但是,我們還需要一個催化劑把它們聚合成一體。
自從根據(jù)我的想法開始招聘擔當測試角色的開發(fā)人員以來,測試組織在不斷壯大?;趯@個團隊的思考,我意識到測試僅僅是我們所負責的工作的一部分。我們的工具團隊開發(fā)了從源代碼庫到編譯框架,再到缺陷數(shù)據(jù)庫的各種工具。我們是測試工程師、發(fā)布工程師、工具開發(fā)工程師和咨詢師。觸動我的是,我們所做的非測試的工作對生產(chǎn)力的提升產(chǎn)生了巨大的影響力。我們的名稱是測試服務(wù),但是我們的職責已經(jīng)遠大于此。
因此,我決定正式把團隊名稱改為工程生產(chǎn)力(Engineering Productivity)團隊。伴隨著稱謂的改變,隨之而來的是文化的革新。人們開始更多地談?wù)撋a(chǎn)力而不是測試和質(zhì)量。生產(chǎn)力是我們的工作,測試和質(zhì)量是開發(fā)過程里每個人都要承擔的工作。這意味著開發(fā)人員負責測試,開發(fā)人員負責質(zhì)量。生產(chǎn)力團隊負責幫助開發(fā)團隊搞定這兩項任務(wù)。
開始的時候,這個觀點還只是一種夢想和志向,我們提出的"給Google加速"的口號聽起來也很空洞,但是,隨著時間的推移和我們的努力,我們實現(xiàn)了這些諾言。我們的工具讓開發(fā)的動作更快,我們幫助開發(fā)人員掃清了一個又一個障礙,消除了一個又一個瓶頸。我們的工具還使開發(fā)人員能夠編寫測試用例,并在每次構(gòu)建時看到這些測試的結(jié)果反饋。測試用例不再只是隔離地運行在某些測試人員的機器上。測試結(jié)果會在儀表盤上顯示,并把成功的版本積累下來,作為應(yīng)用發(fā)布健康性的公開數(shù)據(jù)。我們并不是僅僅要求開發(fā)人員對測試和質(zhì)量負責,我們還提供幫助讓他們可以輕松地達到這些要求。生產(chǎn)力和測試的區(qū)別最終變成了現(xiàn)實--Google的創(chuàng)新能夠更為順暢,技術(shù)債也不會累積了。
最終結(jié)果如何呢?我可不愿這么早就交了底,因為這本書就是要詳細講述這個問題的。作者們花費了巨大精力,根據(jù)自身和其他Googler的經(jīng)歷,把我們的秘訣濃縮成了一套核心實踐。但其實,我們的成功有很多方面,從將構(gòu)建次數(shù)以數(shù)量級式地降低,到"跑完即忘"式的測試自動化,再到開源一些非常新穎的測試工具。在我寫這篇序的時候,生產(chǎn)力團隊已經(jīng)擁有1200名工程師,這個數(shù)量比我在2005年加入Google時整個工程部門的工程師的數(shù)量還要多。生產(chǎn)力品牌的影響力已經(jīng)相當大,我們加速Google的使命已經(jīng)作為工程文化的一部分,被廣泛接受。從我困惑、迷茫地坐在TGIF會議上的第一天到現(xiàn)在,這個團隊已經(jīng)走過了漫長的征途。這期間唯一沒變的是我那頂三色螺旋槳帽,我把它放在我的桌上,作為我們一路走來的見證。
Patrick Copeland是Google工程生產(chǎn)力部門的高級總監(jiān),處于Google整個測試鏈的最頂端。公司里所有的測試人員都最終匯報給Patrick(而他恰好跨級匯報給Larry Page,Google的聯(lián)合創(chuàng)始人和CEO)。Patrick加入Google之前是微軟的測試總監(jiān),并在那里工作了近10年。他經(jīng)常公開演講,在Google內(nèi)部被公認為Google軟件快速開發(fā)、測試和部署技術(shù)的架構(gòu)師。
Google軟件測試介紹
- 質(zhì)量不等于測試
有時,測試和開發(fā)互相交織在一起,達到了無法區(qū)分彼此的程度,而在另外一些時候,測試和開發(fā)又是完全分離的,甚至開發(fā)人員都不知道測試在做些什么
質(zhì)量不等于測試。當你把開發(fā)過程和測試放到一起,就像在攪拌機里混合攪拌那樣,直到不能區(qū)分彼此的時候,你就得到了質(zhì)量。
- 角色
軟件開發(fā)工程師(譯注:software engineer,后文簡稱SWE)是一個傳統(tǒng)上的開發(fā)角色,他們的工作是實現(xiàn)最終用戶使用的功能代碼。他們創(chuàng)建設(shè)計文檔、選擇最優(yōu)的數(shù)據(jù)結(jié)構(gòu)和整體架構(gòu),并且花費大量時間在代碼實現(xiàn)與代碼審查上。SWE需要編寫與測試代碼,包括測試驅(qū)動的設(shè)計、單元測試、參與構(gòu)建各種規(guī)模的測試等,這些測試會在本章的后面做詳細解釋。SWE會對他們編寫、修復(fù)以及修改的代碼承擔質(zhì)量責任。如果一個開發(fā)者不得不修改一個函數(shù),或者這次修改導致已有測試用例運行失敗,或者需要增加一個新的測試用例,他就必須去實現(xiàn)這個測試用例的代碼。開發(fā)工程師幾乎將所有的時間都花費在了代碼編寫上。
軟件測試開發(fā)工程師(譯注:software engineer in test,后文簡稱SET)也是一個開發(fā)角色,只是工作重心在可測試性和通用測試基礎(chǔ)框架上。他們參與設(shè)計評審,非常近距離地觀察代碼質(zhì)量與風險。為了增加可測試性,他們甚至會對代碼進行重構(gòu),并編寫單元測試框架和自動化測試框架。SET是SWE在代碼庫上的合作伙伴,相比較SWE是在增加功能性代碼或是提高性能的代碼,SET更加關(guān)注于質(zhì)量提升和測試覆蓋率的增加。SET同樣會花費近百分之百的時間在編寫代碼上,他們這樣做的目的是為質(zhì)量服務(wù),而SWE則更關(guān)注在客戶使用功能開發(fā)的實現(xiàn)上。
測試工程師(譯注:test engineer,后文簡稱TE)是一個和SET關(guān)系密切的角色,有自己不同的關(guān)注點--把用戶放在第一位來思考,代表用戶的利益。一些Google的TE會花費大量時間在模擬用戶的使用場景和自動化腳本或代碼上。同時,他們會把開發(fā)工程師和SET編寫的測試分門別類地組織起來,分析、解釋、測試運行結(jié)果,驅(qū)動測試執(zhí)行,特別是在項目的最后階段,推進產(chǎn)品發(fā)布。TE是真正的產(chǎn)品專家、質(zhì)量顧問和風險分析師。某些TE需要編寫大量的代碼,而另外一些TE則只用編寫少量的代碼。
- 組織結(jié)構(gòu)
測試是獨立存在的部門,是與專注領(lǐng)域部門平行的部門(橫跨各個產(chǎn)品專注領(lǐng)域),我們稱之為工程生產(chǎn)力團隊。測試人員基本上以租借的方式進入到產(chǎn)品團隊,去做提高質(zhì)量相關(guān)的事情,尋找一些測試不足的地方,或者公開一些不可接受的缺陷率數(shù)據(jù)。由于測試人員并不是直接向產(chǎn)品團隊進行匯報,因此我們并不是簡單地被告之某個項目急需發(fā)布就可以通過測試。我們有自己選擇決定的優(yōu)先級,在可靠性、安全性等問題上都不會妥協(xié),除非碰到更重要的事情。如果開發(fā)團隊想要我們在測試上放他們一馬,他們必須事先和我們協(xié)商,但一般情況下都會被拒絕。
注意 工程生產(chǎn)力團隊會根據(jù)不同產(chǎn)品團隊的優(yōu)先級、復(fù)雜度和其他產(chǎn)品的實際比較后,再來分配測試人員。顯然,有時候我們可能搞錯,實際上也確實出過錯,但總體上來說,這樣會保持實際的需求與不明確的需求之間的某種平衡。
這種測試人員在不同項目之間的借調(diào)模式,可以讓SET和TE時刻保持新鮮感并且總是很忙碌,另外還能保證一個好的測試想法可以快速在公司內(nèi)部蔓延。一個在Geo產(chǎn)品上運用很好的測試技術(shù)或工具,很有可能在Chrome產(chǎn)品中也得到使用。推廣測試技術(shù)方面創(chuàng)新的最佳方式,莫過于把這個創(chuàng)新的發(fā)明者直接借調(diào)過來。
在擁有如此少量測試人員的情況下,Google還可以取得不錯的成果,核心原因在于Google從來不會在一次發(fā)布的產(chǎn)品中包含大量功能。
- 版本管理
金絲雀版本、開發(fā)版本、測試版本、beta或發(fā)布版本、
- 測試類型
小型測試 一般來說(但也并非所有)都是自動化實現(xiàn)的,用于驗證一個單獨函數(shù)或獨立功能模塊的代碼是否按照預(yù)期工作,著重于典型功能性問題、數(shù)據(jù)損壞、錯誤條件和大小差一錯誤等方面的驗證。小型測試的運行時間一般比較短,通常是在幾秒或更短的時間內(nèi)就可以運行完畢。通常,小型測試是由SWE來實現(xiàn),也會有少量的SET參與,TE幾乎不參與小型測試。小型測試一般需要使用mock和fake(譯注:mock fake環(huán)境是實際依賴系統(tǒng)的替代者,會提供相應(yīng)的功能,但這些系統(tǒng)可能不存在,或者缺陷太多不可靠,或者是一些很難模擬的錯誤條件)才能運行。TE幾乎不編寫小型測試代碼,但會參與運行這些測試,來診斷一些特定錯誤。小型測試主要嘗試解決的問題是"這些代碼是否按照預(yù)期的方式運行"。
中型測試 通常也都是自動化實現(xiàn)的。該測試一般會涉及兩個或兩個以上,甚至更多模塊之間的交互。測試重點在于驗證這些"功能近鄰區(qū)"之間的交互,以及彼此調(diào)用時的功能是否正確(我們稱功能交互區(qū)域為"功能近鄰區(qū)")。在產(chǎn)品早期開發(fā)過程中,在獨立模塊功能被開發(fā)完畢之后,SET會驅(qū)動這些測試的實現(xiàn)及運行,SWE會深度參與,一起編碼、調(diào)試和維護這些測試。如果一個中型測試運行失敗,SWE會自覺地去查看分析原因。在開發(fā)過程的后期,TE會通過手動的方式(如果比較難去實現(xiàn)自動化或?qū)崿F(xiàn)的代價較大時),或者自動化地執(zhí)行這些用例。中型測試嘗試去解決的問題是,一系列臨近的模塊互相交互的時候,是否如我們預(yù)期的那樣工作。
大型測試 涵蓋三個或以上(通常更多)的功能模塊,使用真實用戶使用場景和實際用戶數(shù)據(jù),一般可能需要消耗數(shù)個小時或更長的時間才能運行完成。大型測試關(guān)注的是所有模塊的集成,但更傾向于結(jié)果驅(qū)動,驗證軟件是否滿足最終用戶的需求。所有的三種工程師角色都會參與到大型測試之中,或是通過自動化測試,或是探索式測試。大型測試嘗試去解決的問題是,這個產(chǎn)品操作運行方式是否和用戶的期望相同,并產(chǎn)生預(yù)期的結(jié)果。這種端到端的使用場景以及在整體產(chǎn)品或服務(wù)之上的操作行為,即是大型測試關(guān)注的重點。
關(guān)于自動化測試和手動測試的比例,對于所有的三種類型測試,當然更傾向于前者。如果能夠自動化,并不需要人腦的智睿與直覺來判斷,那就應(yīng)該以自動化的方式實現(xiàn)。但在一些情況下需要人類智慧的判斷,如用戶界面是否漂亮、保留的數(shù)據(jù)是否包含隱私等方面,這些還是需要手動測試來完成。
軟件測試開發(fā)工程師
對于功能代碼而言,思維模式是創(chuàng)建,重點在考慮用戶、使用場景和數(shù)據(jù)流程上;而對于測試代碼來說,主要思路是去破壞,怎樣寫測試代碼用以擾亂分離用戶及其數(shù)據(jù)。由于我們假設(shè)的前提是在一個童話般的理想開發(fā)過程里,所以我們或許可以分別雇傭不同的開發(fā)工程師:一個寫功能代碼,而另一個思考如何破壞這些功能(譯注:兩種開發(fā)工程師,分別是功能開發(fā)人員和測試開發(fā)人員)。
功能開發(fā)人員在編寫功能代碼的時候,測試開發(fā)人員編寫測試代碼,但我們還需要第三種角色,一個關(guān)心真正用戶的角色。顯然在我們理想化的烏托邦測試世界里,這個工作應(yīng)該由第三種工程師來完成,既不是功能開發(fā)人員,也不是測試開發(fā)人員。我們把這個新角色稱為用戶開發(fā)人員(譯注:user developer)。他們需要解決的主要問題是面向用戶的任務(wù),包括用例(use case)、用戶故事、用戶場景、探索式測試等。用戶開發(fā)人員關(guān)心這些功能模塊如何集成在一起成為一個完整的整體,他們主要考慮系統(tǒng)級別的問題,通常情況下都會從用戶角度出發(fā),驗證獨立模塊集成在一起之后是否對最終用戶產(chǎn)生價值。
SET的工作
- 開發(fā)和測試流程
工程師團隊的交付物就是即將發(fā)布的代碼。代碼的組織形式、開發(fā)過程、維護是日常工作重點。
公開的代碼庫、和諧的工程工具、公司范圍內(nèi)的資源共享,成就了豐富的Google內(nèi)部共享代碼庫與公共服務(wù)。這些共享的代碼運行依賴于Google的基礎(chǔ)設(shè)施產(chǎn)品,它們在加速項目完成與減少項目失敗上發(fā)揮了很大作用。
工程師們對這些共享的基礎(chǔ)代碼做了特殊處理,形成了一套不成文但卻非常重要的實踐規(guī)則,工程師在維護修改這些代碼的時候都要遵守這些規(guī)則。
* 所有的工程師必須復(fù)用已經(jīng)存在的公共庫,除非在項目特定需求方面有很好的理由。
* 對于公共的共享代碼,首先要考慮的是能否可以容易地被找到,并具有良好的可讀性。代碼必須存儲在代碼庫的共享區(qū)域,以便查找。由于共享代碼會被不同的工程師使用,這些代碼應(yīng)該容易理解。所有的代碼都要考慮到未來會被其他人閱讀或修改。
* 公共代碼必須盡可能地被復(fù)用且相對獨立。如果一個工程師提供的服務(wù)被許多團隊使用,這將為他帶來很高的信譽。與功能的復(fù)雜性或設(shè)計的巧妙性相比,可復(fù)用性帶來的價值更大。
* 所有依賴必須明確指出,不可被忽視。如果一個項目依賴一些公用共享代碼,在項目工程師不知情的前提下,這些共享代碼是不允許被修改的。
* 如果一個工程師對共享代碼庫在某些地方有更好的解決方案,他需要去重構(gòu)已有的代碼,并協(xié)助依賴在這個公用代碼庫之上的應(yīng)用項目遷移到新的代碼庫上。這種樂善好施的社區(qū)工作是值得鼓勵的(譯注:這是Google經(jīng)常提及的“同僚獎金(peer bonus)”。任何工程師如果受到其他工程師正面的影響,就可以送出“同僚獎金”作為感謝。除此之外,經(jīng)理還有權(quán)使用其他獎勵手段。這樣做的目的就是讓這種正向團隊合作形成一種良性循環(huán),并持續(xù)下去。當然,另外還有同事之間私下里的感謝)。
* Google非常重視代碼審核,特別是公共通用模塊的代碼必須經(jīng)過審核。開發(fā)人員必須通過相關(guān)語言的可讀性審核。在開發(fā)人員擁有按照代碼風格編寫出干凈代碼的記錄之后,委員會會授予這名開發(fā)人員一個“良好可讀性”的證書。Google的四大主要開發(fā)語言:C++、Java、Python和JavaScript都有可讀性方面的代碼風格指南。
* 在共享代碼庫里的代碼,對測試有更高的要求(在后面部分會做討論)。
最小化對平臺的依賴。所有工程師都有一臺桌面工作機器,且操作系統(tǒng)都盡可能地與Google生產(chǎn)環(huán)境的操作系統(tǒng)保持一致。為了減少對平臺的依賴,Google對Linux發(fā)行版本的管理也十分謹慎,這樣開發(fā)人員在自己工作機器上測試的結(jié)果,與生產(chǎn)系統(tǒng)里的測試結(jié)果會保持一致。從桌面到數(shù)據(jù)中心,CPU和OS的變化盡可能?。ㄗⅲ何ㄒ徊辉贕oogle通用測試平臺里的本地測試實驗室,是Android和Chrome OS。這些類目不同的硬件必須在手邊進行測試)如果一個bug在測試機器上出現(xiàn),那么在開發(fā)機器上和生產(chǎn)環(huán)境的機器上也都應(yīng)該能夠復(fù)現(xiàn)。
所有對平臺有依賴的代碼,都會強制要求使用公共的底層庫。維護Linux發(fā)行版本的團隊同時也在維護這個底層平臺相關(guān)的公共庫。還有一點,對于Google使用的每個編程語言,都要求使用統(tǒng)一的編譯器,這個編譯器被很好地維護著,針對不同的Linux發(fā)行版本都會有持續(xù)的測試。這樣做本身其實并沒有什么神奇之處,但限制運行環(huán)境可以節(jié)省大量下游的測試工作,也可以避免許多與環(huán)境相關(guān)且難以調(diào)試的問題,能把開發(fā)人員的重心轉(zhuǎn)移到新功能開發(fā)上。保持簡單,也就相對會安全。
Google在平臺方面有特定的目標,就是保持簡單且統(tǒng)一。開發(fā)工作機和生產(chǎn)環(huán)境的機器都保持統(tǒng)一的Linux發(fā)行版本;一套集中控制的通用核心庫;一套統(tǒng)一的通用代碼、構(gòu)建和測試基礎(chǔ)設(shè)施;每個核心語言只有一個編譯器;與語言無關(guān)的通用打包規(guī)范;文化上對這些共享資源的維護表示尊重且有激勵。
使用統(tǒng)一的運行平臺和相同的代碼庫,持續(xù)不斷地在構(gòu)建系統(tǒng)中打包(譯注:打包是一個過程,包括將源代碼編譯成二進制文件,然后再把二進制文件統(tǒng)一封裝在一個linux rpm包里面),這可以簡化共享代碼的維護工作。構(gòu)建系統(tǒng)要求使用統(tǒng)一的打包規(guī)范,這個打包規(guī)范與項目特定的編程語言無關(guān),與團隊是否使用C++、Python或Java也都無關(guān)。大家使用同樣的“構(gòu)建文件”來打包生成二進制文件。
一個版本在構(gòu)建的時候需要指定構(gòu)建目標,這個構(gòu)建目標(可以是公共庫、二進制文件或測試套件)由許多源文件編譯鏈接產(chǎn)生。下面是整體流程。
* (1)針對某個服務(wù),在一個或多個源代碼文件中編寫一類或一系列功能函數(shù),并保證所有代碼可以編譯通過。
* (2)把這個新服務(wù)的構(gòu)建目標設(shè)定為公共庫。
* (3)通過調(diào)用這個庫的方式編寫一套單元測試用例,把外部重要依賴通過mock模擬實現(xiàn)。對于需要關(guān)注的代碼路徑,使用最常見的輸入?yún)?shù)來驗證。
* (4)為單元測試創(chuàng)建一個測試構(gòu)建目標。
* (5)構(gòu)建并運行測試目標,做適當?shù)男薷恼{(diào)整,直到所有的測試都運行成功。
* (6)按要求運行靜態(tài)代碼分析工具,確保遵守統(tǒng)一的代碼風格,且通過一系列常見問題的靜態(tài)掃描檢測。
* (7)提交代碼申請代碼審核(后面對代碼審核會做更多詳細說明),根據(jù)反饋再做適當?shù)男薷?,然后運行所有的單元測試并保證順利通過。
產(chǎn)出將是兩個配套的構(gòu)建目標:庫構(gòu)建目標和測試構(gòu)建目標。庫構(gòu)建目標是需要新發(fā)布的公共庫、測試構(gòu)建目標用以驗證新發(fā)布的公共庫是否滿足需求。注意:在Google許多開發(fā)人員使用“測試驅(qū)動開發(fā)”的模式,這意味著步驟(3)會在步驟(1)和步驟(2)之前進行。
對于規(guī)模更大的服務(wù),通過鏈接編譯持續(xù)新增的代碼,構(gòu)建目標也會逐漸變大,直到整個服務(wù)全部構(gòu)建完成。在這個時候,會產(chǎn)生二進制構(gòu)建目標,其由包含主入口main函數(shù)文件和服務(wù)庫鏈接在一起構(gòu)成?,F(xiàn)在,你完成了一個Google產(chǎn)品,它由三部分組成:一個經(jīng)過良好測試的獨立庫、一個在可讀性與可復(fù)用性方面都不錯的公共服務(wù)庫(這個服務(wù)庫中還包含另外一套支持庫,可以用來創(chuàng)建其他的服務(wù))、一套覆蓋所有重要構(gòu)建目標的單元測試套件。
一個典型的Google產(chǎn)品由許多服務(wù)組成,所有產(chǎn)品團隊都希望一個SWE負責對應(yīng)一個服務(wù)。這意味著每個服務(wù)都可以并行地構(gòu)建、打包和測試,一旦所有的服務(wù)都完成了,他們會在一個最終的構(gòu)建目標里一起集成。為了保證單獨的服務(wù)可以并行地開發(fā),服務(wù)之間的接口需要在項目的早期就確定下來。這樣,開發(fā)者會依賴在協(xié)商好的接口上,而不是依賴在需要開發(fā)的特定庫上。為了不耽擱服務(wù)級別之間的早期測試,這些接口一般都不會真正實現(xiàn),而只是做一個虛假的實現(xiàn)。
SET會參與到許多測試目標的構(gòu)建之中,并指出哪些地方需要小型測試。在多個構(gòu)建目標集成在一起,形成規(guī)模更大應(yīng)用程序的構(gòu)建目標時,SET需要加速他們的工作,開始做一些更大規(guī)模的集成測試。在一個單獨的庫構(gòu)建目標中,需要運行幾乎所有的小型測試(由SWE編寫,所有支持這個項目的SET都會給予幫助)。當構(gòu)建目標日益增大時,SET也會參與到中大型測試的編寫之中去。
- SET是什么?
SET是開發(fā),主要做可測試性方面的工作。
SET首先是工程師角色,他使得測試存活于先前討論的所有Google開發(fā)過程之中。SET(software engineer in test)是軟件測試開發(fā)工程師。最重要的一點,SET是軟件工程師,正如我們招聘宣傳海報和內(nèi)部晉升體系中所說的那樣,是一個100%的編碼角色。這種測試方式的有趣之處在于它使測試人員能盡早介入到開發(fā)流程中去,但不是通過“質(zhì)量模型”和“測試計劃”的方式,而是通過參與設(shè)計和代碼開發(fā)的方式。這會使得功能的開發(fā)工程師和測試的開發(fā)工程師處于相同的地位,SET積極參與各種測試,使測試富有效率,包括手動測試和探索式測試,而這些測試后期會由其他工程師負責。
- SET的介入時機
在項目早期,Google一般不會讓測試介入進來。實際上,即使SET在早期參與進來,也不是從事測試工作,而是去做開發(fā)。絕非有意忽視測試,當然也不是說早期產(chǎn)品的質(zhì)量就不重要。這是受Google非正式創(chuàng)新驅(qū)動產(chǎn)品的流程所約束。Google很少在項目創(chuàng)建初期就投入一大幫人來做計劃(包括質(zhì)量與測試計劃),然后再讓一大群開發(fā)參與進來。Google項目的誕生從來沒有如此正式過。
- 團隊結(jié)構(gòu)
Google產(chǎn)品團隊最初是由一個技術(shù)負責人(tech lead)和一個或更多的項目發(fā)起人組成。在Google,技術(shù)負責人這個非正式的崗位一般由工程師擔任,負責設(shè)定技術(shù)方向、開展合作、充當與其他團隊溝通的項目接口人。他知道關(guān)于項目的任何問題,或者能夠指出誰知道這些問題的細節(jié)。技術(shù)負責人通常是一名SWE,或者由一名具備SWE能力的工程師來擔任。
- 設(shè)計文檔
所有Google項目都有設(shè)計文檔。這是一個動態(tài)的文檔,隨著項目的演化也在不斷地保持更新。最早期的項目設(shè)計文檔,主要包括項目的目標、背景、團隊成員、系統(tǒng)設(shè)計。在初期階段,團隊成員一起協(xié)同完成設(shè)計文檔的不同部分。對于一些規(guī)模足夠大的項目來說,需要針對主要子系統(tǒng)也創(chuàng)建相應(yīng)的設(shè)計文檔,并在項目設(shè)計文檔中增加子系統(tǒng)設(shè)計文檔的鏈接。在初期版本完成后,里面會囊括所有將來需要完成的工作清單,這也可以作為項目前進的路標。從這一點上講,設(shè)計文檔必須要經(jīng)過相關(guān)技術(shù)負責人的審核。在項目設(shè)計文檔得到足夠的評審與反饋之后,初期版本的設(shè)計文檔就接近尾聲了,接下來項目就正式進入實施階段。
作為SET,比較幸運的是在初期階段就加入了項目,會有一些重要且有影響力的工作急需完成。如果能夠合理地謀劃策略,我們在加速項目進度的同時,也可以做到簡化項目相關(guān)人員的工作。實際上,作為工程師,SET在團隊中有一個巨大的優(yōu)勢,就是擁有產(chǎn)品方面最廣闊的視野。一個好的SET會把非常專業(yè)的廣闊視野轉(zhuǎn)化成影響力,在開發(fā)人員所編寫的代碼上產(chǎn)生深遠的影響力。通常來說,代碼復(fù)用和模塊交互方面的設(shè)計會由SET來做,而不是SWE。后面會著重介紹SET在項目的初期階段是如何發(fā)揮作用的。
SET需要熟悉了解所負責的系統(tǒng)設(shè)計(閱讀所有的設(shè)計文檔是一個途徑),SET和SWE都期望如此。
SET早期提出的建議會反饋在文檔和代碼里,這樣也增加了SET的整體影響力。
作為第一個審閱所有設(shè)計文檔的人(也因此了解所有迭代過程),SET對項目的整體了解程度超過了技術(shù)負責人。
對于SET來說,這也是一個非常好的機會,可以在項目初期就與相應(yīng)開發(fā)工程師一起建立良好的工作關(guān)系。
審閱設(shè)計文檔的時候應(yīng)該有一定的目的性,而不是像讀報紙那樣隨便看兩眼就算了。優(yōu)秀的SET在審閱過程中始終保持強烈的目的性。下面是一些我們推薦的一些要點。
#!python
完整性:找出文檔中殘缺不全或一些需要特殊背景知識的地方。通常情況下團隊里沒人會了解這些知識,特別是對新人而言。鼓勵文檔作者在這方面添加更多細節(jié),或增加一些外部文檔鏈接,用以補充這部分背景知識。
正確性:看一下是否有語法、拼寫、標點符號等方面的錯誤,這一般是馬虎大意造成的,并不意味著他們以后編寫的代碼也是這樣。但也不能為這種錯誤而破壞規(guī)矩。
一致性:確保配圖和文字描述一致。確保文檔中沒有出現(xiàn)與其他文檔中截然相反的觀點和主張。
設(shè)計:文檔中的一些設(shè)計要經(jīng)過深思熟慮。考慮到可用的資源,目標是否可以順利達成?要使用何種基礎(chǔ)的技術(shù)框架(讀一讀框架文檔并了解他們的不足)?期望的設(shè)計在框架方面使用方法上是否正確?設(shè)計是否太過復(fù)雜?有可能簡化嗎?還是太簡單了?這個設(shè)計還需要增加什么內(nèi)容?
接口與協(xié)議:文檔中是否對所使用的協(xié)議有清晰的定義?是否完整地描述了產(chǎn)品對外的接口與協(xié)議?這些接口協(xié)議的實現(xiàn)是否與他們期望的那樣一致?對于其他的Google產(chǎn)品是否滿足統(tǒng)一的標準?是否鼓勵開發(fā)人員自定義Protocol buffer數(shù)據(jù)格式(后面會討論Protocol buffer)?
測試:系統(tǒng)或文檔中描述的整套系統(tǒng)的可測試性怎樣?是否需要新增測試鉤子(譯注:testing hook,這里指為了測試而增加一些接口,用以顯示系統(tǒng)內(nèi)部狀態(tài)信息)?如果需要,確保他們也被添加到文檔之中。系統(tǒng)的設(shè)計是否考慮到易測試性,而為之也做了一些調(diào)整?是否可以使用已有的測試框架?預(yù)估一下在測試方面我們都需要做哪些工作,并把這部分內(nèi)容也增加到設(shè)計文檔中去。
google的代碼評審工具 https://github.com/rietveld-codereview/rietveld
- 接口協(xié)議
Google protocol buffer語言(注:Google protocol buffers 是開源的,參見http://code.google.com/apis/protocolbuffers)
為了能夠盡早可以運行集成測試,針對依賴服務(wù),SET提供了mock與fake。
- 自動化計劃
我們首先把容易出錯的接口做隔離,并針對它們創(chuàng)建mock和fake(在之前的章節(jié)中做過介紹),這樣我們可以控制這些接口之間的交互,確保良好的測試覆蓋率。
接下來構(gòu)建一個輕量級的自動化框架,控制mock系統(tǒng)的創(chuàng)建和執(zhí)行。這樣的話,寫代碼的SWE可以使用這些mock接口來做一個私有構(gòu)建。在他們把修改的代碼提交到代碼服務(wù)器之前運行相應(yīng)的自動化測試,可以確保只有經(jīng)過良好測試的代碼才能被提交到代碼庫中。這是自動化測試擅長的地方,保證生態(tài)系統(tǒng)遠離糟糕代碼,并確保代碼庫永遠處于一個時刻干凈的狀態(tài)。
SET除了在這個計劃中涵蓋自動化(mock、fake和框架)之外,還要包括如何公開產(chǎn)品質(zhì)量方面的信息給所有關(guān)心的人。在Google,SET使用報表和儀表盤(譯注:dashboard)來展示收集到的測試結(jié)果以及測試進度。通過將整個過程簡化和信息公開透明化,獲取高質(zhì)量代碼的概率會大大增加。
- 可測試性
為了使SET也成為源碼的擁有者之一,Google把代碼審查作為開發(fā)流程的中心。相比較編寫代碼而言,代碼審查更值得炫耀。
在CL提交審查之前,會經(jīng)過一系列的自動化檢查。這種自動化靜態(tài)檢查所使用的規(guī)則包含一些簡單的確認,例如是否遵循Google的代碼風格指南、提交CL相關(guān)的測試用例是否執(zhí)行通過(原則上所有的測試必須全部通過)等。CL里面一般總是包含針對這個CL的測試代碼,測試代碼總是和功能代碼在一起。在檢查完成之后,Mondrian會給相應(yīng)的CL審閱者發(fā)送一封包含這個CL鏈接的通知郵件。隨后審閱者會進行代碼審查,并把修改建議發(fā)回給SWE去處理。這個過程會反復(fù)進行,直到提交者和審閱者都滿意為止。
提交隊列(譯注:submit queue)的主要功能是保持“綠色”的構(gòu)建,這意味著所有測試必須全部通過。這是構(gòu)建系統(tǒng)和版本控制系統(tǒng)之間的最后一道防線。通過在干凈環(huán)境中編譯代碼并運行測試,提交隊列系統(tǒng)可以捕獲在開發(fā)機器上無法發(fā)現(xiàn)的環(huán)境錯誤,但這會導致構(gòu)建失敗,甚至是導致版本控制系統(tǒng)中的代碼處于不可編譯的狀態(tài)。
規(guī)模較大的團隊可以利用提交隊列在同一個代碼分支上進行開發(fā)。如果沒有提交隊列,通常在代碼集成或每輪測試時都會把代碼凍結(jié),使用提交隊列就可以避免這個問題。在這種模式下,提交隊列可以使得規(guī)模較大團隊就像小團隊一樣,高效且獨立。由于這樣增加了開發(fā)提交代碼的頻率,勢必給SET的工作帶來了較大難度,這可能是唯一的弊端。
- SET的工作流程:一個實例:
略,可以參考具體語言的單元測試。
- 測試執(zhí)行
做代碼編譯、測試執(zhí)行、結(jié)果分析、數(shù)據(jù)存儲、報表展示的通用的測試框架
- 測試規(guī)模
小型測試是為了驗證一個代碼單元的功能,一般與運行環(huán)境隔離,例如針對一個獨立的類或一組相關(guān)函數(shù)的測試。小型測試的運行不需要外部依賴。在Google之外,小型測試通常就是單元測試。
中型測試是驗證兩個或多個模塊應(yīng)用之間的交互。和小型測試相比,中型測試有著更大的范疇且運行所需要的時間也更久。小型測試會嘗試走遍單獨函數(shù)的所有路徑,而中型測試的主要目標是驗證指定模塊之間的交互。在Google之外,中型測試經(jīng)常被稱為“集成測試”。
在Google之外通常被稱為“系統(tǒng)測試”或“端到端測試”。大型測試在一個較高層次上運行,驗證系統(tǒng)作為一個整體是如何工作的。這涉及應(yīng)用系統(tǒng)的一個或所有子系統(tǒng),從前端界面到后端數(shù)據(jù)儲存。該測試也可能會依賴外部資源,如數(shù)據(jù)庫、文件系統(tǒng)、網(wǎng)絡(luò)服務(wù)等。
小型測試是為了驗證一個代碼單元的功能。中型測試驗證兩個或多個模塊應(yīng)用之間的交互。大型測試是為了驗證整個系統(tǒng)作為一個整體是如何工作的。
- 測試平臺對測試規(guī)模的調(diào)度
使用Google測試執(zhí)行平臺運行的一些通用任務(wù)如下。
#!python
開發(fā)人員編譯和運行小型測試,希望立刻就能知道運行結(jié)果。
開發(fā)人員希望運行一個項目的所有小型測試,并能夠快速知道運行結(jié)果。
開發(fā)人員只有在變更代碼出現(xiàn)時,才希望去編譯運行相關(guān)的項目測試,并即刻得到運行結(jié)果。
工程師希望能夠知道一個項目的測試覆蓋率并查看結(jié)果。
對項目的每次代碼變更(CL),都能夠運行這個項目的小型測試,并將運行結(jié)果發(fā)送給團隊成員以輔助進行代碼審查。
在代碼變更(CL)提交到版本控制系統(tǒng)之后,自動運行項目的所有測試。
團隊希望每周都能得到代碼覆蓋率,并實時跟蹤覆蓋率的變化。
上面提及的所有任務(wù),有可能同時并發(fā)提交到Google測試執(zhí)行系統(tǒng)。一些測試可能極度消耗資源,使得公用測試機器處于不可用狀態(tài)達數(shù)小時。另外一些測試可能只需幾毫秒,而且可以和其他幾百個任務(wù)同時在一臺機器上并發(fā)運行。當每一個測試都被標記為小型、中型、大型的時候,調(diào)度運行這些測試任務(wù)就會變得相對簡單一些,因為調(diào)度器已經(jīng)知道每個任務(wù)需要運行的時間,這樣可以優(yōu)化任務(wù)隊列,達到合理利用的目的。
Google測試執(zhí)行系統(tǒng)利用了測試規(guī)模的定義,把運行較快的任務(wù)從較慢的任務(wù)中挑選出來。測試規(guī)模在測試運行時間上規(guī)定了一個最大值,如表2.1所示;同時測試規(guī)模在測試運行消耗資源上也做了要求,如表2.2所示。Google測試執(zhí)行系統(tǒng)在發(fā)現(xiàn)任何測試超時,或是消耗的資源超過這個測試規(guī)模應(yīng)該使用的資源時,會把這個測試任務(wù)取消掉并報告這個錯誤。這會迫使工程師提供合適的測試規(guī)模標簽。精準的測試規(guī)模,可以使Google測試執(zhí)行系統(tǒng)在調(diào)度時做出明智的決定。
類別 | 小型測試 | 中型測試 | 大型測試 | 超大型測試
:---- ---:|:---- ---:|:---------------------:|:---------------------:
時間目標(每個函數(shù))| 10毫秒以內(nèi) | 1秒以內(nèi) | 盡可能快 | 盡可能快
強制時間限制 | 1分鐘之后強制結(jié)束 | 5分鐘之后強制結(jié)束 | 15分鐘之后強制結(jié)束 | 1小時之后強制結(jié)束
資源使用
類別 | 大型測試 | 中型測試 | 小型測試
:---- ---:|:---- ---:|:---------------------:
網(wǎng)絡(luò)服務(wù)(建立一個鏈接)| 是 | 僅本地 | 模擬
數(shù)據(jù)庫 | 是 | 僅本地 | 模擬
訪問文件系統(tǒng) | 是 | 是 | 模擬
訪問用戶界面系統(tǒng) | 是 | 不鼓勵 | 模擬
系統(tǒng)調(diào)用 | 是 | 不鼓勵 | 否
多線程 | 是 | 是 | 不鼓勵
睡眠狀態(tài) | 是 | 是 | 否
系統(tǒng)屬性 | 是 | 是 | 否
- 測試規(guī)模的優(yōu)缺點
大型測試
#!python
測試最根本最重要的:在考慮外部系統(tǒng)的情況下應(yīng)用系統(tǒng)是如何工作的。
由于對外部系統(tǒng)有依賴,因此它們是非確定性的。
很寬的測試范疇意味著如果測試運行失敗,尋找精準失敗根源就會比較困難。
測試數(shù)據(jù)的準備工作會非常耗時。
大型測試是較高層次的操作,如果想要走到特定的代碼路徑區(qū)域是不切實際的,而這一部分卻是小型測試的專長。
中型測試
#!python
由于不需要使用mock技術(shù),且不受運行時刻的限制,因此該測試是從大型測試到小型測試之間的一個過渡。
因為它們運行速度相對較快,所以可以頻繁地運行它們。
它們可以在標準的開發(fā)環(huán)境中運行,因此開發(fā)人員也可以很容易運行它們。
它們依賴外部系統(tǒng)。
由于對外部系統(tǒng)有依賴,因此它們本身就有不確定性。
它們的運行速度沒有小型測試快。
小型測試
#!python
為了更容易地就被測試到,代碼應(yīng)清晰干凈、函數(shù)規(guī)模較小且重點集中。為了方便模擬,系統(tǒng)之間的接口需要有良好的定義。
由于它們可以很快運行完畢,因此在有代碼變更發(fā)生的時候就可以立刻運行,從而可以較早地發(fā)現(xiàn)缺陷并提供及時的反饋。
在所有的環(huán)境下它們都可以可靠地運行。
它們有較小的測試范圍,這樣可以很容易地做邊界場景與錯誤條件的測試,例如一個空指針。
它們有特定的范疇,可以很容易地隔離錯誤。
不要做模塊之間的集成測試,這是其他類型的測試要做的事情(中型測試)。
有時候?qū)ψ酉到y(tǒng)的模擬是有難度的。
使用mock或fake環(huán)境,可以不與真實的環(huán)境同步。
小型測試帶來優(yōu)秀的代碼質(zhì)量、良好的異常處理、優(yōu)雅的錯誤報告;大中型測試會帶來整體產(chǎn)品質(zhì)量和數(shù)據(jù)驗證。
檢驗一個項目里小型測試、中型測試和大型測試之間的比率是否健康,一個好辦法是使用代碼覆蓋率。測試代碼覆蓋率可以針對小型測試、中大型測試分別單獨產(chǎn)生報告。覆蓋率報告會針對不同的項目展示一個可被接受的覆蓋率結(jié)果。如果中大型測試只有20%的代碼覆蓋率,而小型測試有近100%的覆蓋率,則說明這個項目缺乏端到端的功能驗證。如果結(jié)果數(shù)字反過來了,則說明這個項目很難去做升級擴展和維護,由于小型測試較少,就需要大量的時間消耗在底層代碼調(diào)試查錯上。
Google有許多不同類型的項目,這些項目對測試的需求也不同,小型測試、中型測試和大型測試之間的比例隨著項目團隊的不同而不同。這個比例并不是固定的,總體上有一個經(jīng)驗法則,即70/20/10原則:70%是小型測試,20%是中型測試,10%是大型測試。如果一個項目是面向用戶的,擁有較高的集成度,或者用戶接口比較復(fù)雜,他們就應(yīng)該有更多的中型和大型測試;如果是基礎(chǔ)平臺或者面向數(shù)據(jù)的項目,例如索引或網(wǎng)絡(luò)爬蟲,則最好有大量的小型測試,中型測試和大型測試的數(shù)量要求會少很多。
另外有一個用來監(jiān)視測試覆蓋率的內(nèi)部工具是Harvester。Harvester是一個可視化的工具,可以記錄所有項目的CL歷史,并以圖形化的方式展示,例如測試代碼和CL中新增代碼的比率、代碼變更的多少、按時間的變化頻率、按照開發(fā)人員的變化次數(shù),等等。這些圖形的目的是展示隨著時間的變化,測試的變化趨勢是怎樣的。
- 測試運行要求
#!python
每個測試和其他測試之間都是獨立的,使它們就能夠以任意順序來執(zhí)行。
測試不做任何數(shù)據(jù)持久化方面的工作。在這些測試用例離開測試環(huán)境的時候,要保證測試環(huán)境的狀態(tài)與測試用例開始執(zhí)行之前的狀態(tài)是一樣的。
對于沖突:
#!python
兩個測試都要綁定同一個端口,用以接收來自網(wǎng)絡(luò)的數(shù)據(jù)。
兩個測試需要在同一個路徑下創(chuàng)建相同的目錄。
一個測試希望創(chuàng)建并使用一個數(shù)據(jù)庫表,而另外一個測試想刪除這個數(shù)據(jù)庫表。
解決方案
#!python
在測試執(zhí)行系統(tǒng)中,讓每個測試用例獲取一個未被使用的端口,并讓被測系統(tǒng)動態(tài)地綁定到這個端口上。
在測試執(zhí)行之前,為每一個測試用例在臨時目錄下創(chuàng)建目錄和文件,并使用獨一無二的目錄名。
每個測試運行在自己的數(shù)據(jù)庫實例之上,使用與環(huán)境隔離的目錄和端口。這些都由測試執(zhí)行系統(tǒng)來控制。
Google全力維護其測試執(zhí)行系統(tǒng),甚至文檔也非常詳盡。這些文檔存放在Google的“測試百科全書”中,這里有對其運行使用的資源所做的最終解釋。“測試百科全書”有點像IEEE RFC(譯注:IEEE定義的正式標準,RFC是Request for Comment的簡寫),明確使用“必須”或“應(yīng)該”這樣的字樣,并在其中詳細解釋了角色、測試用例職責、測試執(zhí)行者、集群系統(tǒng)、運行時刻的libc、文件系統(tǒng)等。
構(gòu)建系統(tǒng)能定位到錯誤由哪個提交引起,同時還保存了構(gòu)建依賴圖。
測試認證
招聘到技術(shù)能力強的測試人員只是剛剛開始的第一步,我們依然需要開發(fā)人員參與進來一起做測試。其中我們使用的一個關(guān)鍵方法就是被稱為“測試認證”。
測試認證級別摘要
#!python
級別1
使用測試覆蓋率工具。
使用持續(xù)集成。
測試分級為小型、中型、大型。
明確標記哪些測試是非確定性的測試。
創(chuàng)建冒煙測試集合。
級別2
如果有測試運行結(jié)果為紅色就不會做發(fā)布。
在每次代碼提交之前都要求通過冒煙測試。
各種類型測試的整體增量覆蓋率要大于50%。
小型測試的增量覆蓋率要大于10%。
每一個功能特性至少有一個與之對應(yīng)的集成測試用例。
級別3
所有重要的代碼變更都要經(jīng)過測試。
小型測試的增量覆蓋率要大于50%。
新增的重要功能都要經(jīng)過集成測試的驗證。
級別4
在提交任何新代碼之前都會自動運行冒煙測試。
冒煙測試必須在30分鐘內(nèi)運行完畢。
沒有不確定性的測試。
總體測試覆蓋率應(yīng)該不小于40%。
小型測試的代碼覆蓋率應(yīng)該不小于25%。
所有重要的功能都應(yīng)該被集成測試驗證到。
級別5
對每一個重要的缺陷修復(fù)都要增加一個測試用例與之對應(yīng)。
積極使用可用的代碼分析工具。
總體測試覆蓋率不低于60%。
小型測試的代碼覆蓋率應(yīng)該不小于40%。
最初這個計劃在一些測試意識較高的團隊中緩慢試水,這些團隊成員熱衷于改進他們的測試實踐。經(jīng)過在這幾個團隊的成功試驗之后,一個規(guī)模更大的、公司級別的認證競賽開始推行起來了,然后在新加入的團隊中再推行這個計劃就變得容易的多。
#!python
開發(fā)團隊得到許多優(yōu)秀測試人員的關(guān)注,這些測試人員一般都報名成為測試認證教練。在一個測試資源稀缺的文化氛圍里,注冊參加這個項目會吸引到比一般團隊更多的測試人員的加入。
他們獲得專家的指導,并學習到如何更好地編寫小型測試。
他們知道哪個團隊在測試上做的比較好,并向這個團隊學習。
他們能夠向其他的認證級別較低的團隊進行炫耀。
經(jīng)過公司級別的推進,絕大多數(shù)團隊都在不斷向前進步,并意識到這個計劃的重要性。一些在這個計劃中表現(xiàn)不錯的開發(fā)總監(jiān)會得到工程生產(chǎn)力團隊的優(yōu)秀反饋,而嘲笑這個計劃的團隊也會置自身于危險之中。換句話說,在一個測試資源相對稀缺的公司里,哪個團隊會舍得與工程生產(chǎn)力團隊疏遠呢?但并非哪里都是鮮花與掌聲,讓運行這個計劃的負責人來給我們講述完整的故事吧。
試點團隊::① 足夠感興趣;② 沒有太多的冗余代碼;③ 在團隊中有一個測試戰(zhàn)神(對測試足夠的了解的人)。
我們宣布測試認證計劃“正式啟動”的時候,有15個試點團隊在這個計劃的不同級別上運行著。在正式宣布之前,我們在山景城、紐約和其他地點的所有辦公大樓上張貼“神秘的測試認證”的大海報,每個海報上用圖片印著各個試點團隊名字,使用的是內(nèi)部項目名稱,如Rubix、Bounty、Mondrian和Red Tape。海報上唯一的文字是“未來就是現(xiàn)在”和“至關(guān)重要,莫被遺棄”,還有一個鏈接。從喜愛猜謎的Google同事那里,我們得到了大量點擊訪問,多數(shù)人想去一探究竟,還有一些人想去驗證自己的猜測是否正確。同時我們也使用ToTT來宣傳這個新計劃,并把讀者指引到他們能夠得到信息的地方。這是一個信息閃電戰(zhàn)。
宣傳網(wǎng)站上有一些信息,包括為什么測試認證對于團隊很重要,以及用戶可以得到怎樣的幫助。里面強調(diào)指出,參與團隊會從一個很大的測試專家社區(qū)里得到一個測試認證教練,同時還會得到兩個禮物——一個表示構(gòu)建狀態(tài)的發(fā)光魔法球,可以告訴團隊他們的(一般是新的)持續(xù)集成是通過(綠色)還是失?。t色);另外一個是一個漂亮的星球大戰(zhàn)土豆頭工具包。這個被稱為達斯土豆工具包里有三個逐漸變大的格子,每當團隊達到新的測試認證級別時我們都會給予獎勵。各個團隊展示他們的魔法球和土豆頭,為這個計劃吸引來更多好奇的團隊和帶來更好的口碑。
測試圈子里的成員是這個項目的第一批教練和發(fā)言人。隨著越來越多團隊的加入,有許多熱情的工程師幫助造勢,自己也成為其他團隊的教練。
每次我們嘗試說服更多的團隊加入這個計劃的時候,都會與他們逐一討論理由和原因。一些團隊是由于你能使他們信服每一個級別和教練都會幫助團隊在這個領(lǐng)域有所提高而加入的。一些團隊認為他們會有所改善,并堅信這種“官方”級別評定會使他們因為當前正在做的工作得到好評。另外的一些團隊,他們本身的測試成熟度已經(jīng)很高了,但加入這個計劃,會給其他的團隊發(fā)出一種信號,表示他們已經(jīng)很重視測試了。
- SET的招聘(暫略)
參考資料
- 討論 釘釘群21745728 qq群144081101 567351477
- 本文最新版本地址
- 本文英文原版書籍
- 本文源碼地址
- 本文涉及的python測試開發(fā)庫 謝謝點贊!
- 本文相關(guān)海量書籍下載