實習的時候我維護一支 UI 自動化腳本。裡面有一段在測篩選功能:選好條件、點下去、等載入、抓結果。
有一次它跑出「查無資料」。
腳本回了 pass。因為畫面沒有報錯、沒有 crash、流程走完了。
現在我知道那個 pass 不成立。不是因為答案錯,是因為我根本沒有能力判斷它對不對。
| 發生了什麼 | 該回什麼 | |
|---|---|---|
| 真空 | 篩選邏輯正確,資料源剛好沒有符合的項目 | pass |
| 偽空 | 篩選條件傳錯、後端回錯、前端沒渲染出來 | fail |
在畫面上,這兩件事都是同一句「查無資料」。
所以我那支腳本不是判斷錯了,它是沒有判斷。它看到一個空白,然後假設空白代表正常。
這跟 Day 2 我說的那句「那部分我看過了」是同一個毛病,只是這次是腳本在犯。眼睛掃過去沒有不對勁,就當作沒問題。
測試要成立,得有兩樣東西:一個動作,和一個你事先知道的預期結果。
後面那樣東西在測試裡有個名字,叫 oracle——判斷對錯的依據。
「點下去,看會怎樣」不是測試,那是操作。
「點下去,應該出現三筆,結果出現零筆」才是測試。
篩選功能的 oracle 特別難拿,因為資料會變。同樣的條件,昨天有十筆,今天可能真的就是零筆。你沒辦法把上週的結果存起來當標準答案。
而且前端跟後端常常各執一詞——後端說我回對了,前端說我照著顯示了,bug 卡在中間。
只要你的功能是「對一個會變動的資料集做條件篩選」,這個問題就會找上你。訂房平台的星等加價位、電商的品牌加價格區間、求職網站的職類加薪資範圍,全都一樣。
我後來整理過幾種做法,這裡挑三條實習生用得上的。
第一條:拿後端當 oracle。
直接打 API 問「符合這個條件的有幾筆」,再跟畫面比。後端回 0,畫面也空,那是真空;後端回 5,畫面空了,那是前端的 bug。
這是最乾淨的做法,代價是你得有 API 可以打、有權限、看得懂回傳。
第二條:自己種資料。
測試前先確保資料庫裡有一筆一定符合條件的東西,然後再篩。這樣「空」就一定是錯的。
代價是你得能寫入測試環境的資料,而且要記得清乾淨。
第三條:雙向驗證。
同一個篩選,跑兩次相反的條件。篩「價格 100 以下」跟篩「價格 100 以上」,兩邊的數量加起來應該等於全部。
如果兩邊都是空的,那全部也該是空的;如果不是,篩選壞了。
這條的好處是它不需要額外權限,只需要你多想一步。實習生最有機會做到的就是這條。
技術解法你上網查得到,而且每個團隊的限制不一樣。
我真正希望有人早點告訴我的是這句話:
當你發現自己說不出「正確的結果應該長什麼樣」,那個測試就還沒成立。
不是還沒寫完,是還沒成立。
我實習的時候寫了不少那樣的腳本。它們會跑、會綠燈、會出現在報表上。但它們之中有一部分從來沒有真的在驗證什麼,它們只是在重複一組動作,然後回報「沒有爆炸」。
Day 8 講測試是抽樣。這篇講的是更前面的一步:你取的那一匙,得有辦法嘗出味道,否則舀幾次都一樣。
寫下一個測試案例之前,先把這句話填完:
「如果這裡是對的,我應該看到 ___;如果是錯的,我會看到 ___。」
兩個空格都填得出來,才動手。填不出來,先去把 oracle 找到——那通常要去問人,而不是去改腳本。
明天聊:我花兩天確認一件事做不出來,然後把它丟給主管。那次我什麼都沒解決,但我覺得那是實習時做得最對的一個決定。