|
51cmm (2005-06-16 11:25:38)
現(xiàn)在,許多游戲項(xiàng)目要么跳票嚴(yán)重,要不就是發(fā)布時Bug多多。當(dāng)然,這樣的現(xiàn)象并不僅存于游戲工業(yè)。例如,根據(jù)2001Standish集團(tuán)發(fā)表的那份聲名狼藉的報告“極度混亂”所表述的,70%以上的軟件項(xiàng)目要么被取消,要么嚴(yán)重的超時和超支。然而,游戲是軟件開發(fā)復(fù)雜性的最佳代表,不同技能的人需要協(xié)同工作,這也就是某些人所說的游戲項(xiàng)目中高風(fēng)險因素所在。 軟件項(xiàng)目延期、Bug滿天飛和失敗的原因是多種多樣的,但看起來除了隨產(chǎn)品特性不斷變化之外,測試和品質(zhì)管理是永恒的問題。以我們的經(jīng)驗(yàn)來看,相當(dāng)多數(shù)的游戲開發(fā)工作室完全依靠人工的方式來測試游戲引擎、開發(fā)工具和游戲代碼,幾乎沒有采用自動化過程測試。很巧,在2002GDC的圓桌會議:游戲中的純軟件工程,只有18%的與會者表示他們參與的項(xiàng)目采用了自動化測試。 在2000年,我們的客戶,當(dāng)時新成立的中間件公司對我們的3D引擎的穩(wěn)定性和大量的BUG抱怨頻頻,我們第一次想到了自動化測試。直到那時,每當(dāng)完成一個新特征,我們還是依靠人工測試,并且使用這些特征開發(fā)出技術(shù)演示供市場部使用。我們在徹底分析了情況后得出以下結(jié)論,我們的軟件質(zhì)量問題主要和我們測試方法有關(guān): *人工測試不夠全面和徹底,因?yàn)樗鼉H僅花費(fèi)了很多時間。代碼在修改或添加之后,它本應(yīng)運(yùn)行預(yù)定義的人工測試集來保證修改不會產(chǎn)生新的問題。人工測試花費(fèi)的時間越來越多,并給開發(fā)者帶來挫折感,打擊他們執(zhí)行測試的積極性。而且,測試的工作量使得開發(fā)者不愿意改進(jìn)或優(yōu)化現(xiàn)有的代碼。 *當(dāng)開發(fā)者測試他們自己的代碼時,他們總是不愿意(潛意識?)執(zhí)行最苛刻的測試用例,因此就導(dǎo)致了最有可能出錯之處也是最不可能被全面測試到這樣的情形。 因此,我們決定采用自動化測試,從開發(fā)一個新SDK部件開始。結(jié)果是鼓舞人心的,最終我們把它推廣到所有的SDK部件開發(fā)中去。測試框架極限編程,由Kent Beck和Martin Fowler總結(jié)的一系列方法和經(jīng)驗(yàn),帶來了自動化測試的流行。一般來說,自動化測試指無需用戶干預(yù),用來驗(yàn)證軟件產(chǎn)品中的功能子集的代碼和數(shù)據(jù)。它可以是用來測試某個特定類方法(通常稱為單元測試),也可以是用來測試程序功能性的集成測試(功能測試)。 為了促進(jìn)自動化測試進(jìn)程,有許多開源代碼的單元測試框架,比如CPPunit(C++專用)或Nunit(.Net專用)。這些測試框架提供了GUI來運(yùn)行測試集并提供測試結(jié)果反饋。根據(jù)你的項(xiàng)目,也許需要根據(jù)你的游戲進(jìn)行一些額外的功能擴(kuò)展和自定義,例如支持跨平臺。這些測試框架的內(nèi)容,一個單元測試對應(yīng)一個函數(shù),測試類由多個單元測試組成,并且包含一個開始和結(jié)束測試的方法(例如載入和卸載一幅地圖)。這些測試類可以放在分離的執(zhí)行文件中,例如 DLL文件,也可以與主項(xiàng)目在一起。除此之外,測試類應(yīng)該存放在產(chǎn)品代碼之外的文件中,這樣的話,他們就可以很方便的從版本發(fā)布中移除。 物理引擎的簡單測試代碼,如果任何一個VTEST條件沒有滿足,那么測試就失敗。該測什么?當(dāng)要決定測試的范圍時,實(shí)用第一。一般來說,為簡單的功能編寫單元測試是沒有意義的,比如常見的 getter和setter方法。為了讓自動化測試物有所值,被測試的代碼至少應(yīng)該是可能會產(chǎn)生錯誤的,比如,發(fā)射一束穿透游戲場景的光線并且返回它穿過的任何幾何物體的方法(光線測試),然后將返回的結(jié)果與編寫測試用例的作者提供的預(yù)期結(jié)果作比較。 到底是只為類的公用接口編寫測試用例(黑盒測試)還是要兼顧類的私有成員(白盒測試),是一個有爭議的問題。通常來說,黑盒測試比白盒測試粗糙,它們只能檢查一個操作的最終結(jié)果,不能檢查內(nèi)部中間狀態(tài),它們對于被修改的測試代碼比較遲鈍。剛才提到的光線測試功能可能被全部重寫(比如原先的版本運(yùn)行效率不夠),但是它返回的結(jié)果沒有變化。這時,白盒測試用例就需要跟著重寫,然而黑盒測試可以繼續(xù)用來檢測代碼修改后,所產(chǎn)生的結(jié)果是否與原先一致。 因此,我們認(rèn)為自動化測試中,測試范圍只要包括類的公有成員就夠了,畢竟,類的內(nèi)部修改比它接口修改要頻繁得多。 回歸測試 特別是在游戲開發(fā)領(lǐng)域,大多數(shù)情況下,把測試結(jié)果和用例編寫者提供的數(shù)據(jù)手工作比較是不太現(xiàn)實(shí)的。例如,檢測與復(fù)雜的幾何體碰撞的交點(diǎn),人工提供相關(guān)測試數(shù)據(jù)幾乎不可能。相反,將測試結(jié)果與早期代碼產(chǎn)生的結(jié)果數(shù)據(jù)相比較,被稱為“回歸測試”。用例編寫者可以評審參考數(shù)據(jù),例如,使用簡化圖形的碰撞物體,如果被證實(shí)是正確的,它就可以一直用于測試。這樣,自動化測試可以幫助你確認(rèn)新代碼產(chǎn)生的結(jié)果與原先的一致。 代碼功能測試會生成非常復(fù)雜的輸出數(shù)據(jù),比如游戲的圖形渲染引擎,回歸測試是唯一可行的自動化測試。以圖形渲染引擎為例,所有圖形測試以輸出最終平臺相關(guān)的圖形文件為結(jié)果。一旦自動化測試開始運(yùn)行,渲染出來的圖形文件與樣本圖形文件逐一像素的進(jìn)行比較,如果有差異,那么測試失敗。為了減少樣本圖形文件的存占用,你可以使用圖形快照來進(jìn)行測試。 圖形回歸測試的優(yōu)勢在于即使是肉眼難以發(fā)現(xiàn)的微小差異也不會被漏掉。除非人們對這個場景非常熟悉,否則很難會有人注意到場景中缺失的一個陰影或一個物體或者某個光源的R值與B值被錯換了。而回歸測試就不會放過任何一個這樣的錯誤。 必須注意到,任何情況下,回歸測試的樣本數(shù)據(jù)都是自動生成的。樣本數(shù)據(jù)也許是平臺相關(guān),特別涉及到渲染輸出的時候,因此,它也許要被生成多次,即使是這樣,當(dāng)渲染通道發(fā)生變化導(dǎo)致生成的圖形文件有所改變,樣本數(shù)據(jù)也要重新生成。為了不打擊開發(fā)者編寫回歸測試的積極性,要做到只需點(diǎn)擊框架用戶界面上一個按鈕就可以重新生成新的參考數(shù)據(jù)。 如何把所有的整合在一起 包括游戲在內(nèi)的所有應(yīng)用,完整的測試集合包括單元測試和回歸測試。單元測試適合于測試底層功能性、基礎(chǔ)庫文件和平臺類庫。上層的各種功能特征集成測試可以使用回歸測試。根據(jù)結(jié)果,你可以有選擇的重構(gòu)或優(yōu)化你的邏輯或引擎代碼,回歸測試一旦失敗,你會馬上發(fā)現(xiàn)出問題的地方,單元測試失敗可以讓你精確的定位出錯之處。 知道代碼被你編寫的自動化測試覆蓋得范圍是非常有好處的,你可以使用代碼覆蓋率調(diào)查工具(BullseyeCoverage/AQtime)。代碼覆蓋率分析會告訴你,你的代碼哪些被調(diào)用,也可以提示你測試集合中的疏漏之處。測試覆蓋率應(yīng)該是多少,無法精確定量,盡管它取決于被測試的代碼。細(xì)小的方法無需測試,調(diào)試用的函數(shù)也不必測試。并且,幾乎所有的項(xiàng)目都會包括一些“死”代碼,也就是不會被調(diào)用到的代碼,那么,這些代碼自然也不用測試??偠灾F(xiàn)實(shí)中,我們見過的使用自動化測試的游戲和中間件項(xiàng)目中測試覆蓋率大致是55%到70%。 編寫友好的測試代碼 必須承認(rèn),并不是所有的代碼都能使用自動化測試。以單元測試為例,嚴(yán)格的面向?qū)ο螅己玫念惡秃瘮?shù)模塊化封裝設(shè)計(jì)可以大大提高它的測試效率。類的接口越多,為它編寫的單元測試就越多。同樣,過多的使用C++的友元也會增加編寫的難度,甚至無法為該類編寫(黑盒)單元測試用例。 在寫代碼的時候,要時刻牢記保持良好的測試性。在開發(fā)過程中,就會變成可行但是單調(diào)乏味的工作,有時候它需要很好的結(jié)構(gòu)性。要在游戲開發(fā)中使用,以下幾點(diǎn)必須牢記: *所有的回歸測試都取決于明確的行為。比如,使用隨計(jì)算法的尋徑系統(tǒng)可以提供一個初始化隨機(jī)種子的公共方法使得角色的行動決策更復(fù)雜多變。這個方法在隨后的測試中可以被用來確保角色始終選取同樣的路徑。 *同樣,回歸測試中要避免與幀數(shù)相關(guān)的情況;否則,有真實(shí)物理特性的物體或渲染輸出也許會和以前的數(shù)據(jù)不同,特別是當(dāng)結(jié)果來自不同的機(jī)器或者不同的編譯條件(debug 和release)。在測試時,使用恒定的虛擬幀數(shù)就可以避免這樣的問題。 * 嚴(yán)重依賴于用戶輸入的軟件很難測試,比如游戲內(nèi)置的編輯系統(tǒng)或者游戲工具。這樣的話,把UI 和邏輯代碼嚴(yán)格的區(qū)分開會有所幫助。在我們的游戲工具里, UI界面里每個用戶動作會執(zhí)行一條或多條簡單的腳本指令。每條腳本指令可以很明確的重現(xiàn)用戶的原意。這樣,測試用例可以簡單的執(zhí)行這些指令并且與樣本數(shù)據(jù)作比較就可以(比如導(dǎo)出地形文件)。 也可以使用GUI捕捉工具來測試UI,但我們發(fā)現(xiàn)這并不是個好辦法。UI會經(jīng)常改變,哪怕一個按鈕僅僅移動幾個像素也會使捕捉軟件失效,GUI捕捉工具也許會幫倒忙。 關(guān)于測試的疑問:我們真的可以節(jié)省時間么? 多數(shù)情況下,一個開發(fā)團(tuán)隊(duì)想要在開發(fā)過程中使用自動化測試,大多數(shù)成員都會對它抱以質(zhì)疑的態(tài)度。畢竟,與其花這點(diǎn)時間寫測試用例,還不如去寫邏輯和引擎的代碼。根據(jù)我們在游戲和其他領(lǐng)域的工作中使用自動化測試的經(jīng)驗(yàn)來看,編寫測試代碼會額外增加30%工作量。初看,在時間和資金上這也許是很大的開銷,然而,你要意識到這樣做,省去了人工測試所花費(fèi)的時間。 自動化測試可以看作在開發(fā)前期投入,在開發(fā)過程中贏利。大多數(shù)的代碼修改,包括Bug修改,都可能會引入更多問題導(dǎo)致程序宕機(jī)。所以,理論上說,一旦代碼有所改變,就必須測試所有可能被影響的代碼。自動化測試無需人工干預(yù)就可以完成,它們縮短了開發(fā)過程。而且由于自動化測試可以簡單快速的發(fā)現(xiàn)修改的代碼是否能有效地運(yùn)行,因此也就鼓勵開發(fā)者優(yōu)化和改進(jìn)現(xiàn)有的代碼。 對我們來說,自動化測試幫助開發(fā)者編寫更穩(wěn)定和可靠的代碼。哪怕是一開始對它抱有懷疑態(tài)度的開發(fā)成員也欣賞它所提供早期反饋的特性,在開發(fā)過程中,它也可以更早的發(fā)現(xiàn)Bug。開發(fā)者的工作壓力和負(fù)荷隨著項(xiàng)目的開展日益加大,盡早的發(fā)現(xiàn)和解決Bug也可以避免給開發(fā)關(guān)鍵時期帶來額外的壓力。 在開發(fā)Vision引擎的時候,我們收集了一些數(shù)據(jù)來研究為提高代碼穩(wěn)定性而實(shí)施自動化測試的有效性。2001年早期,全部依靠人工測試的引擎第一個 release版本開發(fā)完成,盡管我們已經(jīng)進(jìn)行了很全面的測試,但是每個月,我們的在線技術(shù)支持?jǐn)?shù)據(jù)庫依然會收到上百個來自客戶的Bug報告。2001年 9月,我們對已有的引擎功能和新增的特征實(shí)施自動化測試。這樣,即使我們現(xiàn)在的工作量很大,開發(fā)進(jìn)展也很正常,每月Bug報告的數(shù)量銳減(現(xiàn)在大概是5到 10個)。 必須強(qiáng)調(diào),這些圖表只是反映了單元測試用例數(shù)量和每月Bug數(shù)量兩者之間的相互關(guān)系,不能將它理解為必然的因果關(guān)系。當(dāng)然,從2001年到2004年,我們在如何編寫健壯的代碼上學(xué)到了很多,在這段時間內(nèi),開發(fā)團(tuán)隊(duì)的人數(shù)變動頻頻,但是,這些明顯的差異足以說明穩(wěn)定性的提升部分歸功于使用了自動化測試。 游戲中自動化測試的局限性 盡管使用自動化測試對于游戲開發(fā)來說獲益匪淺,但是也有其局限之處。顯然,很難用它來測試游戲的平衡性,也不太可能用它來測試游戲性和畫面的美觀性。在這幾年里,我們總結(jié)了一些編寫自動化測試的要點(diǎn),重點(diǎn)如下: *測試最重要的模塊(比如,最復(fù)雜和最常用的)。對那些最有可能出問題或者不會破壞原先設(shè)計(jì)的重構(gòu)任務(wù)進(jìn)行自動化測試,性價比最高。 *當(dāng)上層功能性測試難以進(jìn)行的時候,把精力集中在不同的子系統(tǒng)上。例如,你也許不能通過自動化測試來驗(yàn)證AI系統(tǒng)是否正常工作,但你可以測試當(dāng)一個怪獸的體力低于一定數(shù)值的時候,它是否會“投降”。 *用壓力測試來驗(yàn)證你的代碼的強(qiáng)壯性。如果你的游戲在極端條件下運(yùn)行的很好,比如,每秒有2000個怪獸出生和死亡,一個場景中同時放入500個有真實(shí)物理特性的物體,一幅地圖輪流載入200次,那么玩家作一些異常操作時,宕機(jī)的可能性就會小很多。 *在修改Bug前,也為它編寫測試用例。這樣的話,可以確保這些Bug在今后的版本中不會重現(xiàn)。 *回歸測試。例如,圖像或狀態(tài)比較的話,使用指定的測試場景要比使用產(chǎn)品地圖更容易維護(hù)。如果你認(rèn)為測試用產(chǎn)品數(shù)據(jù)可能會經(jīng)常變動,那么你最好使用小的測試場景。否則,不斷的生成新的參考數(shù)據(jù)會使得開發(fā)團(tuán)隊(duì)產(chǎn)生疲倦和厭煩的情緒。 * 測試用例越簡單越好,不要奢望有非常大的覆蓋面。搭建一個易維護(hù)和可擴(kuò)展的自動化測試是一個長期的任務(wù)。一般來說,“底層”代碼,例如算術(shù)、碰撞檢測和渲染,更容易進(jìn)行自動化測試,對于游戲性和完整的游戲測試來說,還是需要經(jīng)過QA人員親自測試。當(dāng)然,QA部門的注意力也要從技術(shù)轉(zhuǎn)移到與游戲性相關(guān)的問題上去。“到A房間后,因?yàn)橥L(fēng)口前面的箱子太高了,所以出不去”這樣的報告就會取代“當(dāng)我的角色轉(zhuǎn)動的時候,屏幕上出現(xiàn)了很多扭曲的三角面”。 持續(xù)集成 在一個復(fù)雜的軟件項(xiàng)目中引入自動化測試,你會發(fā)覺運(yùn)行它也需要一定的時間,我們看到的一些項(xiàng)目甚至需要幾個小時。如果讓開發(fā)者在他們的開發(fā)用機(jī)上運(yùn)行的話,測試會完全占用他們的機(jī)器,影響工作,那么結(jié)果就是他們不去運(yùn)行測試用例,很顯然,沒有被運(yùn)行的用例是沒有任何價值的。 解決方法就是搭建一臺或多臺專用的自動化測試機(jī)。它同時還運(yùn)行版本管理軟件(Subversion/CVS/Perforce),一旦發(fā)現(xiàn)提交了新代 碼,那么代碼就會被Check out并編譯,測試用例也會自動運(yùn)行。最后,系統(tǒng)會將測試結(jié)果報告以email的形式自動發(fā)送給最近提交代碼的開發(fā)者。 完全自動化、重復(fù)的 build和測試過程,這種過程每天運(yùn)行多次,在極限編程中,我們把它稱為:持續(xù)集成。為了更好的實(shí)行持續(xù)集成,像 Cruise Control或者Anthill這樣的開源代碼工具可以將版本管理軟件和自動build工具,例如ANT,整合起來。使用這樣的工具,可以很輕松的搭建適合自己的持續(xù)集成系統(tǒng)。 我們發(fā)現(xiàn)搭建專用持續(xù)集成服務(wù)器使得開發(fā)過程變得更順暢,開發(fā)者可以更專注于自己的工作。與此同時,測試可以被很好的運(yùn)行,一旦提交了錯誤的代碼,持續(xù)集成系統(tǒng)會自動通知開發(fā)者和項(xiàng)目經(jīng)理,因此開發(fā)者也可不必為此分心。自動化,自動化! 自動化測試和持續(xù)集成的使用為我們在游戲和工具的開發(fā)上帶來了極大的收益。例如,持續(xù)集成服務(wù)器根據(jù)Wiki中的變化,每天自動生成CHF (windows幫助文件)文件。而且,使用ANT和CruiseControl來制作軟件自動分發(fā)包會非常容易。這樣一來,用最新的代碼(或最新的 tag)創(chuàng)建一個完整的分發(fā)包就是舉手之勞。 自動化過程中的自動化測試執(zhí)行,例如測試框架中的常規(guī)單元和回歸測試,他們不是用來檢查錯誤,而是用在相同環(huán)境下得到測試結(jié)果來衡量和比較引擎的性能(系統(tǒng)配置的結(jié)果以 XML文件格式存放在版本管理軟件系統(tǒng)上)。如果當(dāng)前的結(jié)果比參考結(jié)果差很多,那么測試失敗,反之,它就成為了新的參考結(jié)果。 性能測試是一種特殊的回歸測試。當(dāng)引擎代碼被重構(gòu),我們通過它來確保修改不會降低引擎原有的性能。這樣,就迫使我們時刻關(guān)注代碼的運(yùn)行效率和對代碼的優(yōu)化工作,可以避免遇到在實(shí)際運(yùn)行中,速度突然變慢的現(xiàn)象發(fā)生。 結(jié)論 根據(jù)我們的經(jīng)驗(yàn),使用自動化測試和持續(xù)集成可以使開發(fā)團(tuán)隊(duì)工作更有效而開發(fā)出更好、穩(wěn)定、簡單的軟件。而且,減少人工測試也可以減少開發(fā)團(tuán)隊(duì)的壓力和工作負(fù)荷,可以在開發(fā)過程中盡早的發(fā)現(xiàn)Bug。 當(dāng)然,自動化測試不會使你的游戲想當(dāng)然成為暢銷品。但毋庸置疑,它會使各類開發(fā)人員甚至玩家活得更自在。 |
|
|