逆向思維:從「它能動」到「我要弄壞它」

#破壞性測試 #探索式測試 #測試思維 #QA 實戰 #QA 思維

逆向思維:從「它能動」到「我要弄壞它」 大部分人第一次接觸測試,學的都是「跟著需求走」——規格說按這個按鈕會跳到下一頁,你就確認它有沒有跳。這是正向測試,少不了,但它只抓得到「已知的錯誤」,也就是你明確預期某件事應該發生、但它沒發生。 真實世界裡最危險的 bug,往往出現在沒人想到要測的地方。切換到逆向思維,意思是你主動去假設系統在哪裡會崩潰、使用者會用什麼你沒預料到的方式操作它,然後刻意走那條路。 正向 vs 逆向 正向測試的邏輯是:「根據規格,這個動作應該產生這個結果。我去確認它有。」你跟著 happy path 走,逐一打勾。這種測試確認了系統在理想條件下能動,對版本驗收很有用。 逆向測試的邏輯則完全反過來:「這個系統在什麼情況下會壞?壞了之後會發生什麼事?」你從失敗結果出發,倒推能導致那個結果的所有路徑。 對照看就很清楚: 正向:「使用者填完表單按送出,系統顯示成功訊息。」 逆向:「使用者在按送出的瞬間網路斷線——系統顯示成功嗎?資料有沒有存進去?頁面會不會卡死?」 這不算刁難。系統在理想狀態下能動,只是最低標準。 從失敗場景倒推 把逆向思維套到具體功能,起點是問自己:「這個流程,最慘的情況是什麼?」 以付費流程為例。正向路徑測的是「輸入卡號、確認付款、跳到成功頁」。但失敗場景有很多層: 扣款成功,但網路在跳轉成功頁的瞬間中斷 。使用者看到的是什麼?系統認為付款成功了嗎?訂單狀態有沒有正確寫入? 使用者在確認付款後狂點上一頁 。會不會觸發兩次扣款?後端有冪等保護嗎? 付款中途強制背景殺 App ,回來之後狀態是「待付款」還是「已付款」?這兩種如果顯示錯,一個讓使用者重複付款,一個讓訂單憑空消失。 每一個場景,都是從「失敗結果」倒推來的——先想「這件事最壞會怎樣」,再去設計測試去踩它。 質疑假定前提 開發時為了讓系統跑起來,必然帶入一堆假設:「使用者會看提示」、「使用者照流程一步步走」、「輸入的資料格式合理」、「沒有人會故意在奇怪的時機打斷流程」。 這些假設讓系統在正常情況下能用,但也是 bug 的溫床。逆向思維要求你逐一把這些假設翻出來質疑: 假設使用者看提示 ——如果他不看呢?一個必填欄位沒填,系統只靠紅色邊框提示,手機用戶可能完全沒注意就繼續送出,結果收到不明意義的 500 錯誤。 假設使用者照順序走 ——如果他收藏了第三步的 URL,直接跳進來呢?前兩步沒走完的狀態,系統處理得了嗎? 假設輸入合理 ——姓名欄輸入 emoji、電話欄貼進一段文章、年齡填負數——這些不是惡意攻擊,是真實使用者的日常失誤。系統有沒有優雅地擋住,還是直接炸掉? 開發者的盲區,常常來自他自己就是「照規矩走的使用者」。逆向思維的工作,就是替那些不照規矩走的人把關。 心態轉變 剛開始做逆向測試,最常遇到的阻力是一句話:「這種情況不可能發生。」 使用者在按下付款的精確毫秒網路斷線?扣款瞬間連點上一頁?在姓名欄輸入兩千字的文章?聽起來都匪夷所思。 我自己就被這句話打臉過。計時進行到一半,使用者切去用別的 App,過一陣子回來,發現這次計時被判定成「放棄」,可是他根本沒按過放棄。目前的推測是:Android 在背景記憶體吃緊時把 App 的程序收掉,App 回來時走的是冷啟動,沒走恢復流程,計時狀態就這樣丟了。要模擬這個情境也不用等運氣,開發者選項裡把背景程序數量限制調到最低,切出去再切回來就行。「使用者不會那樣做」在這裡根本不成立,因為動手的是作業系統。 只要使用者夠多、操作夠久,百萬分之一的機率一定會被踩到。所以該問的是:發生了之後系統怎麼反應? 破壞性測試要逼出的是系統的 優雅降級 :壞掉可以接受,但要讓使用者知道發生什麼事、下一步怎麼做,別只丟一片白畫面,或一個只有工程師看得懂的錯誤碼。