上一篇關于測試用例設計的博文《設計測試用例的四條原則》中,介紹了設計測試用例的四條原則。本篇結合最近工作遇到的一個小插曲,介紹一下測試用例本身Passed和Failed的有效性問題。
我所在的團隊上個 Sprint有一項很重要的工作,就是進行Stress 測試,需要編寫自動化用例測試模擬程序長時間的執行,并觀察其內存消耗是否呈現合理的增長趨勢,以及有沒有內存的泄漏等問題。同事很快編寫好了測試用例, 并執行了個把個小時,得出了初步的數據。數據顯示程序的表現相當完美,不僅內存沒有陡峭的突變,甚至連大斜率的線性增長也木有,基本呈現為一條略有波動的 水平直線。非常讓人振奮,這樣的表現打消團隊之前的擔心,完成這項工作所需的時間也將大大小于之前的預估。
我對這項測試也非常感興趣, 并和同事進行了一些交流,想深入了解一些更詳細的情況,比如測試數據規模、執行的時間長短、測試數據分布等,隨著交流的深入同事突然意識到似乎測試代碼似 乎有些不大合乎常理的表現,進一步調試發現代碼中一段生成數據的代碼并沒有正確生成數據,雖然測試仍在執行但輸入的數據沒有,測試只是在空轉,并沒有真正 執行被測程序的邏輯,所以整個曲線才呈現為一條水平線。
這件事本身是個小問題,但其背后隱藏著一個值得我們深究的問題:當你的測試用例Passed的時候,被測產品果真是正確的嗎?仔細想想這個問題,可以得到一些對我們的測試工作有意的思考:
1. 自動化測試需要有詳細的日志輸出,以便于診斷測試的確切執行情況。
自動化測試用例的執行過程對我們來說是一個黑盒過程,我們一般只是看到它的結果是Passed或者Failed。如果這個黑盒過程本身就是錯誤的,如本 文一開始所給出的例子,結果是Passed就沒有任何意義了。而且這樣的Passed只會是給問題雪上加霜,減少了發現問題的可能性。
2. 測試人員特別是自動化測試工程師,應該對那些看似完美的東東多些疑問,多些探究精神,在經過客觀途徑驗證之前時刻保持謹慎的樂觀。
從某個角度講,經常Failed測試用例并不值得你太擔心,而那些從來都是Passed的用例,應該是值得你抽時間檢查的對象。
3. 測試用例要么Passed要么 Failed,看似簡單的結果,但其中還是有些值得深究的內容的。
任何一個測試用例實際上是肩負著雙重責任: 其一,保證在被測功能正確的情況下,測試用例應該是Passed;其二,則是在被測功能異常的情況下,測試返回Failed。一般的情況下,我們只是驗證 了第一種情況后就算完成,并將用例提交到用例管理庫或者代碼庫中。很少真正有人去驗證一下在被測試功能異常的情況下,測試用例確實Failed。這樣的用 例驗證可以總結為如下的模式:
Passed –> Passed –> Passed –> …-> Passed? or Failed? |
之所以會有這樣的情況,首先,是因為從意識上講,大多數人都認為測試中對被測功能行為的判斷以足夠強壯,但其實這種沒有客觀佐證的判斷并不可靠;其次, 很多用例的實現和執行多是在被測功能實現之后才開始,這時的被測功能剛實現出來,并經過開發人員反復調試修改,絕大多數情況下都是正確的,由于產品代碼已 經提交,此時很難再有簡單的途徑模擬出錯誤的功能行為,以驗證測試用例Failed的情況。
解決的辦法有兩種:一、盡可能尋找途徑去模擬被測功能的異常;二、再就是合理選擇實現測試用例的時間。很多情況我們的用例是為了覆蓋已有的Bug而添加的,以避免回歸缺陷。這樣的測試用例最好是在Bug修復之前就實現,那么它一定是Failed,這個機會就可以驗證出Failed情況。
擴展一下這個話題,從用例Failed/Passed路徑這角度上看,測試驅動開發(Test Driven Development,TDD)的模型更為合理和自然。因為,TDD強調先有測試用例,再實現產品功能代碼,先實現的測試用例必然是經過一系列的Failed之后,最終達到Passed,其模型可以總結如下:
Failed –> Failed –> Failed –> …–> Passed |
TDD的原理保證了測試用例一定是由Failed開始,到Passed結束,所以不用費心去模擬功能異常以得到Failed結果,同時保證了用例對Failed和Passed都一定進行了驗證。
4. 產品的質量有測試來監控,那么誰來監控測試本身的質量呢?人、過程和工具。
人-測試人員需要更有責任心,保持對任何問題的謹慎樂觀和探究精神;過程-測試計劃和用例的交叉評審,測試代碼也要進行review,同時選擇合理的時機實現測試;工具 – 利用代碼覆蓋來探究測試用例有效性。
總之,我們在編寫和實現測試用例的時候,除了實現基本功能之外,還要多留意的用例(特別是自動化用例)Passed和Failed有效性,經常容易被忽略地是Failed有效性,所以要盡可的尋找途徑來驗證其有效性。