程式碼審查“查”什麼(2):測試

至秦發表於2015-10-01

在上一篇我們談了很多可以在程式碼審查時留意的事情。現在我們會聚焦這個關注點:在測試程式碼中找什麼。

本文假定:

  • 你的團隊已經為程式碼寫過自動化測試。
  • 測試在持續整合(CI)環境下定期執行。
  • 審查的程式碼已經經過自動編譯和測試流程,結果也通過了。

這篇中我們會將介紹審查者在檢視測試時需要考慮的事情。

新的或修改的程式碼有測試嗎?

無論是修改 bug 還是新功能開發,幾乎沒有新程式碼不需要一個新的或更新過的測試去覆蓋它。甚至類似效能這樣的非功能性修改,也被證明往往需要經過測試驗證。如果在程式碼審查中沒有測試,作為審查者你應該問的第一個問題是“為什麼沒有測試?”。

測試有覆蓋到程式碼中令人困惑或者複雜的部分嗎?

比提出“有測試嗎?”這個問題更進一步是要回答這個問題,“重要的程式碼是否被至少一個測試覆蓋?”。

檢查測試覆蓋率無疑是應該自動化的。但我們不僅僅可以檢查覆蓋率的明確百分比,還可以使用覆蓋率檢測工具來確保被覆蓋到的程式碼位於正確的位置。

考慮下面這個例子:

你可以檢查新程式碼(應該容易識別,特別是當你使用類似 Upsource工具)的測試覆蓋率報告以確保充分覆蓋。

上面這個例子,審查者可以讓作者增加一個測試去覆蓋 303 行 if 判斷為真的情況,因為測試工具標記304-306 行為紅色,說明他們沒有被測試到。

對於任何團隊而言,100 % 的測試覆蓋都是不現實的目標,深入瞭解哪些程式碼需要被覆蓋到,比工具得出的數字更有用。

你特別想檢查所有的邏輯分支和複雜的程式碼都有被覆蓋到。

我能理解這些測試麼?

進行測試,提供滿意的測試覆蓋率是一件事,但如果我這個人無法理解這些測試,那它們的使用就被限制了。當它們出了問題該怎麼辦?很難知道要如何修復它們。

考慮下面這個測試:

這是一個很簡單的測試,但是我並不完全確定它測試什麼。它是測試 save 方法?還是 getMyLongID ?而且為什麼同樣的事需要做兩遍?

下面測試的意圖可能更清楚:

闡述測試目的所採取的特定步驟,取決於你使用的語言、庫、所在團隊和個人喜好。這個例子證明通過選擇清楚的名字、內聯常量和增加註釋,作者可以讓一個測試對於開發者而言更容易閱讀,而不僅是他(她)自己。

這些測試需要滿足什麼要求?

這是一個需要專門知識的領域。無論這些稽核的程式碼需要滿足的需求是在正式文件裡,或許在一張使用者故事卡中,還是在使用者提交的 bug裡,被審查的程式碼都需要滿足一些基本要求。(譯者注:在scrum開發流程中,使用者故事 User-Story 是從使用者的角度來描述使用者渴望得到的功能,通常寫在一張卡片上)

審查者應該找到最初的需求來確認:

  1. 無論是單元測試、端對端測試、還是其它的測試,這些測試是否滿足這些要求。比如,如果要求是“允許特殊字元‘#’,‘!’ 和 ‘&’ 出現在密碼欄位”,就應該有一個在密碼欄位使用這些值的測試。如果測試使用其它的特殊字元,則不能證明程式碼符合要求。
  2. 測試需要覆蓋所有的要求。在我們特殊字元的例子中,要求可能繼續“……如果輸入了其它特殊字元,給使用者提示一個錯誤資訊”。審查者在這裡應該檢查是否有一個測試來確認當使用一個錯誤字元會發生什麼。

我可以考慮沒有被現有測試覆蓋到的用例嗎?

通常我們的要求不是清晰明確。在這種情形下,審查者應該考慮最初的 bug、問題、用例中沒有考慮到的邊界條件。

例如,我們有一個新功能,即“讓使用者可以登入系統”,審查者應該想:“如果使用者輸入的使用者名稱為空會發生什麼?”。或者“如果系統中不存在該使用者,會發生什麼錯誤?”。如果被審查程式碼有這些測試,審查者就比較有信心程式碼本身會處理這種情況。反之,如果這些異常用例不存在,審查者就不得不仔細檢查程式碼,看它們是否有正確處理。

如果程式碼裡有但沒有相應的測試,要由團隊決定你們的策略 —— 是否需要讓作者加上這些測試?或者你覺得通過程式碼審查保證邊界條件被覆蓋到就好了?

這些測試是否有說明程式碼的限制條件?

審查者經常會看到審查程式碼中的限制條件。這些限制條件有時是故意設計的 —— 例如,一個批處理最多隻能處理 1000 個條目。

一種說明這些刻意限制條件的方法就是明確地測試他們。在上個例子,我們可以用一個測試來證明當批處理大小超過 1000,會有某種異常發生。

自動化測試中,不必表明這些限制條件,但如果作者寫了一個測試表明他們實現中的這個限制,這就意味著這些限制是有意的(有文件說明的)而不是疏忽造成的。

審查程式碼中的測試型別、測試級別正確嗎?

例如,如果單元測試就足夠了,作者還需要做昂貴的整合測試麼?他們寫的效能微基準能不能在 CI 環境下以一致方式有效地執行呢?

理想情況下自動化測試會盡可能快地執行,這樣就不需要用昂貴的端對端測試去檢查所有型別的功能。用一個數學運算或者布林邏輯檢查的函式,可以很好地替代方法級單元測試。

有沒有針對安全性的測試?

程式碼安全性可以從程式碼審查中受益。我們後續將有一篇安全方面的文章,但就測試而言,我們可以編寫測試覆蓋一些常見問題。例如,我們上面提到的登入程式碼,我們可以寫一個測試,看如果沒有授權我們是否無法進入網站中被保護的區域(或稱為保護 API 方法)。

效能測試

在上篇中我談到效能是審查者需要檢查的部分。自動化效能測試是另外一類測試,我本可以在本篇探討,但後面會寫一篇在程式碼審查中具體看效能方面的文章,我們在那裡再討論這種型別的測試。

審查者也可以寫測試

不同組織有不同的程式碼審查方法 —— 有時非常明確地要求作者負責所有的程式碼改動,有時會和審查者協作由審查者自己提交程式碼的評審建議。

無論採取哪種方法,作為審查者你會發現,寫一些額外的測試去玩一下審查的程式碼,對於理解程式碼是很有幫助的。類似地,你也可以啟動UI介面嘗試一下新功能,同樣也是很有意義的。有些方法和工具可以很容易被用來試驗程式碼。從團隊的利益出發,在程式碼審查中要讓程式碼和玩程式碼變得儘可能容易。

提交額外的測試作為審查的一部分當然很好,但也不是必須的,例如這個實驗已經給我這個審查者滿意的答案。

總結

無論你在組織中如何執行,做程式碼審查有很大好處。程式碼審查可以在程式碼整合到主線之前,就發現程式碼中可能出現的問題。這個階段,開發者還記得來龍去脈,修正問題的成本也不高。

作為一個程式碼審查者,你應該要檢查最初的開發者放在他(她)程式碼中的想法,哪些情況下會變壞,處理邊界條件,用自動化測試“記錄”預期的行為(正常條件和異常情況)。

如果審查者查詢已有的測試,檢查測試的正確性,那麼你們團隊對程式碼會很有信心。而且,如果這些測試在 CI 環境下被定期執行,你可以看到這些程式碼一直可以工作 —— 他們提供了自動化迴歸檢查。如果程式碼審查者很看重他們審查的程式碼,要求高質量的測試,那麼這個程式碼審查的價值在審查者按下“接受”按鈕後,還會延續下去。

打賞支援我翻譯更多好文章,謝謝!

打賞譯者

打賞支援我翻譯更多好文章,謝謝!

任選一種支付方式

程式碼審查“查”什麼(2):測試 程式碼審查“查”什麼(2):測試

相關文章