source: http://www.kirinichiban.com/

真的好還是假的好 — 談測試的資料

Yu-Song Syu
Kuma老師的軟體工程教室
8 min readOct 22, 2017

--

我們花了這麼多時間談測試,也寫了一些測試,在寫測試的過程中,難免會碰上資料的問題。雖然Mock技術可以幫我們避免掉一些狀況,尤其是Continuous Delivery一書中有提到,在單元測試中,你要盡量少用資料庫,如果真的非得用,那也一定要用『記憶體中的資料庫』。為什麼?

很簡單,因為耦合度。在學理上,不只是模組與模組之間,資料與邏輯之間應該也要是低耦合的。來,再跟我說一次:

資料與邏輯之間應該也要是低耦合的。

當你脫離了資料內容的羈絆,你就能專注在邏輯上,如此一來,你才能認真呈現出『正確的產品』,而不只是『能運作的產品』。這句話現在講也許比較抽象,我們先記在心裡,晚點會再回來探討深入的內容。

本文的目標讀者

本文目標讀者必須符合三種條件:

  1. 和我一樣資質平庸,需要正確邏輯才能產出正確結果。
  2. 和我一樣追求邏輯正確,而不是只追求結果正確。
  3. 你處理線上問題的態度是『找出產品的邏輯錯誤』,而不只是『讓產生出來的資料正確』。

一直以來,我都歡迎任何人來閱讀我的文章,但是這一篇比較特別,我想要先定義我的目標讀者。因為,如果你不在我的目標讀者內,這篇文章對你來說讀起來會非常不舒服,會想要反駁,然而跟讀者吵架不是我撰寫本文的目的。

我只是想要把工作做好,不增加技術債,不想給後續維護的人添麻煩而已。

自動測試的資料應該要自己產生,然後馬上消滅

實作上你其實很難真的把邏輯和資料完全脫鉤,這需要非常嚴謹的程式與測試的設計。而事實上在做整合測試與驗收測試時,你也不可以像單元測試那樣排除資料內容。相反地,你肯定會需要準備、操作,並且驗證資料。

有人會推崇,拿正式資料來當作測試資料,也有人退而求其次,拿共用測試環境已存在的資料集來測試,不夠或壞掉時再來補或建。

請容我再提醒,如果你不是前述本文的目標讀者,請你趕快離開,因為你還有大好前程,千萬不要浪費在以下文章,因為那對你的職業生涯沒有幫助。

回到主題,前述的做法在現今軟體業界並不罕見,但是這種做法即使現實生活中運行得很好,但其實是有根本上的問題。我用以下圖片來解釋原因:

首先,我們從得到需求,分析出邏輯,分別依『邏輯』實做出產品與測試,其相互關係如上圖所示,這沒有問題吧?如果你在程式運行一段時間後,拿真實資料來作後續的測試,大概會像下圖這樣:

請先了解一件事:我們做測試的目的,就是要『驗證產品有沒有邏輯上的錯誤』,對吧?那麼試想,萬一產品的邏輯實作有部分瑕疵,那麼由這份產品製造出來的資料,再拿去驗證產品,正確性究竟如何呢?他如何反映出產品的邏輯瑕疵呢?所以,我不建議用正式資料來驗測產品正確性。

那麼,我們就在測試環境的共用資料庫建造資料吧!那麼也許你的世界會變成這個樣子:

你可以從上圖發現兩個問題。第一,共用測試環境的資料由眾人共用,你沒辦法保證誰在什麼時候對哪一筆資料做了什麼。不要騙自己,你就是沒辦法。也許你治軍嚴謹,你說我規定每個RD都只能碰自己產生的資料,別人的都不准碰。問題是你怎麼保證?在『確保每個人在同一個資料庫都只動自己的資料』這件事上,你也許要下非常大的苦工。這些苦工,很可能超出你維護程式碼的成本,再決定這麼做之前,您一定得三思才行。

再說了,系統本身肯定或多或少有一些核心設定吧?這些核心設定也很可能因為要做不同測試而必須設定成不同值,譬如同一張表的同一個欄位,當小明在測甲狀況時需要它是A值,小華在測乙狀況時需要它是B值,小英…,well you know the rest. 就更別提程式的不同版本對於同一格資料的定義或格式可能不一樣了,那複雜度簡直瞬間飆升。真的要花心思或是定規定來維護也行,只是:

其次,更重要的,在你的測試執行完畢後,原始資料肯定在這過程中被更動了。不是吧?你不是以為就這樣放著,下次的驗測還是能重現一樣的邏輯與結果吧?那麼,當下次你還要再驗測時,你是要從頭再造所有一樣的資料嗎?還是你要發揮童子軍精神,自己的髒亂自己掃,循著產品程式邏輯,把剛剛過程中所有動過的資料通通恢復成原來的樣子?不管是哪種,我想複雜度都應該不低才是,並且:

試想,在這樣複雜又共用的情況下,當產品驗測出錯誤,就很有可能是資料被改錯了,這還是小事。當驗測正確時,你真的有信心是你的產品邏輯正確的原因嗎?你哪來的信心?我先說我不敢。我對我的資質可沒那麼有信心,我只相信邏輯的正確性而已…

那麼,該怎麼做才對呢?就要回到我們本段一開始說的了:自動測試的資料應該要自己產生,然後馬上消滅,如下圖:

測試資料與測試本身,單純只來自邏輯,當要驗測不同狀況時,就依該狀況設計資料,並且在每個測試結束時刪除,清空資料庫。如果不方便清空資料庫,至少也要清空資料表。

這樣一來,測試和測試之間不互相有關連性,於是當任何一個測試失敗了,你馬上知道是哪一段邏輯做錯了。同時,共用資料庫產生的複雜性也不見了,流程簡化,你可以專注在邏輯正確性,而不要花公司給你的薪水去抓因人為失誤而造成的測試失敗。

這很重要,因為這是員工與公司之間雙贏的局面。

實務上該怎麼進行

如果要做到上述的工作模式,你有兩種方式:

  1. DB schema進入版控,並讓每個人都可以在本機環境一鍵製造出與正式環境相同的DB schema。
  2. DB schema進入版控,並且測試時使用in-memory DB技術,達到模擬一人一DB的目的。

以上兩種方式,都有一個先決條件,就是DB schema要進入版控。因為唯有DB schema進入版控,RD才不用費心思去抓一個根本不屬於程式邏輯錯誤的問題,也不用再花時間定期去抓正式環境的schema回來倒。

當然,DB schema進入版控有非常非常多的好處,不只是提高測試效率而已。如果你的公司還沒做到這件事,你只好先暫時手動定期追一下schema的修正,並且向天祈求,祈求這件有益無害的事儘早在你的工作環境中發生。

大師是怎麼說的

針對這個主題,大師 Jez Humble 與 Dave Farley 特別用了一整頁的篇幅來闡述他們的看法,我們先來看看原文:

文中提到了,在驗收測試中,對於『複雜狀態』的依賴程度越小越好,重點是要讓程式在開始測試前,處在一個固定的『初始狀態』。

這裡兩位大師的用詞就更嚴格了,用了『抵制』來表達他們對於依賴真實資料進行測試的態度。

取而代之的,你可以維持一份相對小的資料集,每次測試都倒出來用,再在需要時適度調整值。這也是一個不錯的方法,但要注意隨時跟上真實資料庫的schema更新就是了。

值得注意的是,兩位大師並沒有完全抹煞真實資料的價值,在進行容量測試時,真實資料還是很適合的。這也很合理,因為用真實資料,在data set大小上,比較能反應真實狀況。

不要把退燒藥當維他命吃

私以為,真實資料另一個好用的地方在於正式環境出狀況時,可以快速還原並重現異常狀況,讓RD可以很快的找出問題癥結點,並進行修復。

所以我認為在工作時,真實資料就像是效果極強的退燒藥,在緊急狀況來臨時可以救你一命。然而你可以想像,一個人如果天天把退燒藥拿來當維他命吃,會發生什麼事。他也許一直不會發燒,但是維持身體健康所需的營養份都會慢慢不足,久而久之,就會變成一個『健康有問題,但是並不會發燒』的人了。

您不會放任您的產品變成這個樣子,對吧?相信您的老闆也不會樂見。

分別在最適當的時機使用人造資料與真實資料,正是我們在邁向好的軟體工程之路,應該學習並恪守的工作方式。

--

--