蒼時弦也
蒼時弦也
資深軟體工程師
發表於

優雅的 RSpec 測試 - 撰寫測試的方式

撰寫測試的方式有很多種,如何為軟體加入測試也是一門深奧的學問。我個人是比較推薦使用 A-TDD(Acceptance Test Driven Development,驗收測試驅動開發)跟 TDD(Test Driven Development,測試驅動開發)兩種方式來進行開發。

種類

一般來說,我們在討論測試時,常常會提到像是 Unit Test(單元測試)、整合測試(Integration Test)以及 TDD、BDD(Behavior Driven Development,行為驅動開發) 等等關鍵字,實際上他們對應的是範圍跟類型的差異。

單元測試、整合測試討論的是測試的「範圍」也就是測試的單位有多大,以單元測試來說通常是以一個物件、模組(Functional 類型語言可能是一系列方法的集合)左右的大小,至於整合測試可能會是一兩個功能的搭配,因此通常「範圍越大」提升的「覆蓋率」越大卻也越不精細。

至於 TDD 跟 BDD 我認為是不能單獨比較的,前者是一種「方式」表示以撰寫測試來作為開發功能的前提,而後者則是以思考使用者行為的前提來撰寫測試,並且加以實現,其實仍然是可以用「先寫測試」的方式進行。

Acceptance Test Driven Development

在比較完整的學習過「敏捷開發」後,我最推薦的就是「驗收測試」驅動開發的方式,簡單來說就是我們所有開發的功能都是以通過「功能檢查」作為目標的。

像是我們在 Rails 專案經常會使用的 Capybara 就是一種驗收測試框架,因為驗收測試大多是描述「實際使用的情況」因此我們會需要模擬瀏覽器的行為,並且關注在於「使用者」能做的事情。

規格如果要求的是「看到 Hello World 顯示在畫面上」我們的測試就是檢查畫面能不能看到 Hello World 這段文字即可,如何實現的實際上並不重要,即使是「直接寫死」也沒有關係。

當我們完成這個測試條件後,就符合了敏捷開發的堪用(Done)狀態,使用者是可以馬上使用這個產品,但可能不符合「預期」因此我們會繼續的增加「條件」像是「只有登入時才能看到 Hello World 顯示在畫面上」逐步完善功能。

以這樣的方式開發,其實不管是「先寫」還是「後寫」測試都沒有關係,不過如果使用像是 Cucumber 這類工具撰寫測試時,就能先讓驗收的對象「確認規格」符合預期,也更便於溝通,因此「先寫測試」的優點才被體現出來。

Test Driven Development

測試驅動開發跟驗收驅動測試開發不太一樣的地方在於我們是以「測試」為前提進行開發的,因此就會是「先寫測試」來實踐,然而這件事情並非完全沒有幫助的。

很多時候,我們都清楚開發的系統是要盡可能的解耦合、具備可測試性等等特性,然而實際撰寫出來的實作卻往往是高度耦合、難以被測試的。

但是,如果我們轉換思考方式以「被測試」的前提下去思考,其實就能夠將「可測試性」的問題先解決掉,至少我們可以先讓實作是容易被「測試」的。

更進一步的會發現,假設我們希望實作「小範圍」的測試,也就是整個測試的過程中要盡可能減少相依物件的生成、沒有第三方服務的依賴,就必須更好的去設計一個物件,在這樣的前提下實作出來的程式碼自然會有比較低的耦合和較高的可測試性。

最後,我們的程式碼剩下一個不太理想的地方就是 Code Smell(壞味道)的部分需要注意,一部分可以利用靜態分析工具解決掉風格、常見的問題,最後就是考驗一個工程師的水準。

也就是說,如果以「程式設計」的能力來看,撰寫測試本身可以讓一個工程師的水準提高到「產出穩定程式」的水平,剩下無法透過任何方法提升的能力,大多是設計類的知識,也就是架構、商業邏輯(或者說 Domin Knowledge)、演算法等等直接反應「基礎是否扎實」和「經驗是否豐富」的能力,但是在我們考慮這些問題之前,需要讓自己的實力來到「標準」的水平。


如果想在第一時間收到更新,歡迎訂閱弦而時習之在這系列文章更新時收到通知,如果有希望了解的知識,可以利用優雅的 RSpec 測試回饋表單告訴我。