[譯]Unity – Unit testing part 1 – Unit tests by the book

最近終於正式面對要把測試導進專案中的狀態,Unity 前陣子也釋出了它專用的測試工具「Unity Test Tools

關於測試目前也出了幾篇文章講解,看看覺得不錯,就順便不負責任大致翻譯了一下。

如果文中有任何很卡的地方,煩請指教了XD

如果你是個開發者,我假設你已經聽過 unit test 了。我想大部分的人都曾經寫過,但有多少 unit test 是你認為"好的" unit test 呢?Unit test frameworks 僅僅是一個接一個地呼叫清單上的 method 而已,但 method 真正會執行的東西,並不是 framework 所關心的。只要在清單上雙擊你喜歡的 pizza 就可以送到家的功能是多麼棒!為何不用 unit test frameworks 列出所有選項來節省撰寫 GUI 的時間呢!這樣就代表你有了一份訂購 pizza 的測試套件了嗎?

一個 unit test framework 就只是用來寫測試,但並非所有的測試都會是(正確的) unit test。接著先來解釋這個訂購 pizza 的範例,並且想像一個你想要測試的訂購系統。這個測試應該要能驗證當我按下 “訂購" 時,能夠正確觸發呼叫。在這個測試裡應該要能模擬一個最單純的流程,但你應該不會真的想要在每次測試的時候真的收到 pizza 吧?

So what’s wrong with that test?

先從測試範圍開始吧!「Unit Test」 誠如其名,測試一個工作單位。有些人定義一個 unit test 等同測試一個 method,但這樣的定義過於狹隘,將之定義成獨立的邏輯概念(single logical concept)會比較好。測試並不應該真的去和 pizza 店溝通和訂購。而是要測試按鈕按下後,從系統送出的訂購資訊是正確的。

How do I verify that then?

我們假設該 pizza 店有個線上訂購系統,然後我們的程式能送出訂購 pizza 的 HTTP請求(HTTP request)。因為我們並不是要真的訂購 pizza,我們可能要產生一個自用 server,應該要能夠模擬原始 server 的行為,但不用真的送出 pizza。這樣的作法雖然不會太糟,但這會讓我們的測試需要依賴外部資源以及網路通信。另外,我們要如何知道咱們的假 server 有和原來的一樣運作?我們必須要測試這個假 server 麼?不!你應該要在更低的層級(level)做驗證來取代假server。
(譯者註解:下面這段一時間不知到怎麼翻比較順暢…求指教)
You should validate that the object responsible for network communication would make the call to the server without actually making that call.
關於 call,我指的是 HTTP request。這個 call 在你的 code 中應該要真的發生,但它就只是假裝回覆(通常來說,這段 code 在測試模組中應該要和實際使用時一模一樣)。我們也希望測試是在記憶體中執行的,而不用使用其他資源。為此,我們得要仿造一些物件給 mocking frameworks 或是為測試需求做一些特別的執行(implementation)。

利用 interface 降低模組間的耦合吧!

What if the payment is done by 3rd party system?

支付系統(payment system)會將我們連上第三方網站,並期望我們輸入你的信用卡號…這真是一個預算殺手。我們明確地想要跳過這個步驟,並不僅僅是因為我們可能會被處理信用卡這個部分搞爆;同時也希望不用在每一次執行測試的時候都需要輸入信用卡號。
當然我們可以"雇用"一個工讀生來為我們做這件事(並讓他/她得到一個無價的體驗)。或是,我們可以有更聰明的做法。
真正的 unit test 是需要全自動的,而不應該需要任何使用者的互動。我們可以再弄一次模擬對象(mock object)來應對,模擬可以透過覆寫系統的某些行為,讓我們可以簡化或跳過某些訂購處理的步驟。In this case,我們模擬付費模組並讓它馬上確認咱們的付款,而不用把我們導向其他地方。另外,這會讓我們可以控制整個測試。想像一下,如果第三方伺服器沒有反應或是非常慢,那麼我們所有的測試都將會失敗。

訂購 pizza 的測試範例:

Great… anything else?

還有些東西可以讓你的測試更完美,這和 unit test 沒有很直接的關係。可讀性(readability)和可維護性(maintainability)會讓之後接管你的測試的人,可以輕易的理解並更改。可讀的測試同時也可以是你的產品的使用說明書。節省撰寫使用文件的時間可以讓你寫更多測試!

永遠不要使你的測試需要依賴其他東西。永遠都不應該需要去顧慮執行順序!如果需要依賴其他組件,這會讓你的測試難以除錯和維護。
如果一個測試失敗是因為前一個失敗所造成的,顯然就是這個測試是依賴它的。你的程式碼的真實狀態就會因為誤導的結果而隱蔽。讓測試們共享設置(setup),但一定要讓他們各自獨立

最後但並非最不重要的,你應該要把執行時間考慮進來。有些人習慣將 unit test 視為編譯(compilation)的一部分。我想你不會希望編譯佔用太多時間,因此你得要讓你的測試盡可能的快速

Summary

Unit tests 是一般測試套件中很重要的一部份,也通常是所有類型的測試的基底。視覺化這個概念,看看這個測試金字塔,描繪出一個在你的專案中,各種測試健全的分布。

So the original pizza ordering wasn’t that bad in the end?

沒那個必要。我的重點在於展示什麼是 unit test。End-to-End (譯者註解:這個我不知道啥…)的情況也是自動化測試的一種選擇,但你不應該讓你的測試套件 base on them。在金字塔中越往上走,測試的維護和偵錯將會越發困難和緩慢。Integration tests 和 UI tests 也都很重要,取決於你的平衡點。

這些在理論上都很美好,但你現在應該要先想想這些東西要如何在 Unity 中運用。為了運行時的效能,Unity 會有一些限制影響其測試性。Lack of interface 序列化就是其中一個。但並不是所有的 code 都需要序列化。我之後會再寫關於這些限制的解決辦法。

下一篇將會介紹關於如何設計有測試性的 Monobehavior。敬請期待!

原文:「Unit testing part 1 – Unit tests by the book

發表迴響

在下方填入你的資料或按右方圖示以社群網站登入:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / 變更 )

Twitter picture

You are commenting using your Twitter account. Log Out / 變更 )

Facebook照片

You are commenting using your Facebook account. Log Out / 變更 )

Google+ photo

You are commenting using your Google+ account. Log Out / 變更 )

連結到 %s