REST API 測試從狀態碼語意開始
REST 賦予狀態碼特定意義,而用戶端仰賴這些意義。與其假設它成立,不如明確寫成斷言。
建立資源回傳 201,並附上資源位置,而不是只回傳 200 帶一段內容、其他什麼都沒有。
找不到就回 404,沒有權限就回 403。 對沒有權限的情況回傳 404,是某些團隊刻意的選擇;但對不存在的資源回傳 403,就只是個 bug。
無效的輸入回傳 422 或 400,而且要一致。選定一個,再檢查每個端點都遵守。
絕對不要在回應內容裡塞錯誤、卻回傳 200。 這種做法很常見,而且會逼每個用戶端都寫特殊處理。
冪等性
PUT 和 DELETE 應該是冪等的。呼叫兩次後狀態要相同,第二次也不該產生錯誤。這件事很容易做錯,也很容易檢查:呼叫兩次,然後斷言。
第二次 DELETE 應該回 404 而不是 500,道理也一樣。用戶端會重試,而不耐重試的端點,會把一次短暫的網路異常變成使用者看得到的失敗。
你的服務宣稱遵循的慣例
| 分頁 | 完整走訪一遍,拿到的筆數是否等於集合宣稱的總數?分頁邊界上差一筆的情況極為常見。 |
| 篩選與排序 | 無法辨識的篩選條件會被拒絕,還是默默忽略?默默忽略等於自信滿滿地回傳錯誤資料。 |
| 部分更新 | PATCH 只會改動有送出的欄位,還是悄悄把其餘欄位設成 null? |
所有檢查底下的共同關鍵
要對回應內容做斷言,而不只是狀態碼。該有一筆紀錄的地方卻回傳 200 加一個空清單,這種情況能通過所有寫過的狀態碼斷言。光是養成這個習慣,在 REST API 測試中揪出的真實缺陷,就比任何慣例檢查都多。
四個問題
一套 API 測試能不能撐過第一年,取決於四件事:會過期的工作階段、只存在於執行期的值、彼此相依的呼叫,以及沒人清理的資料。TestSprite 以 Auto-Authentication、Dynamic Variables、Dependency Chains 和 Auto-Cleanup 處理這四件事,詳見 API 測試文件。
值得先寫下來的慣例
在測試 API 是否遵循自家慣例之前,得先有人把慣例講清楚;而多數團隊都是在這個過程中才發現,大家的想法並不一致。
四個問題就能定調大部分的事。建立資源回傳什麼狀態碼,有沒有附上資源位置?當呼叫方無論如何都無權查看時,不存在的資源該回 404 還是 403?無法辨識的查詢參數是拒絕還是忽略?PATCH 把沒帶到的欄位視為維持原狀,還是設成 null?
這些問題都沒有放諸四海皆準的答案,卻全都是用戶端所仰賴的選擇。把四個答案寫下來只要二十分鐘,就能把「想做得符合 REST」這種模糊的意圖,變成真正可以斷言的東西,而這是一切能被測試的前提。
不必全部自己寫,也能拿到覆蓋範圍
自動產生的測試計畫會依據規格文件或一次探索掃描,涵蓋功能、結構描述、授權、錯誤處理與邊界等類別,預設就包含上述大部分的慣例檢查。
終端機
npm install -g @testsprite/testsprite-cli
testsprite setup
如果你不想安裝任何東西,儀表板也能做到同樣的事。命令列能做的其他所有事情,都寫在 CLI 儲存庫。
如果建置流程歸另一個團隊管, GitHub App 是阻力最小的選擇:它就是一個 webhook,不會更動你儲存庫裡的任何東西,並且會在建置流程回報新版本上線時觸發。如果你希望這項檢查直接顯示在儲存庫裡,一個 GitHub Actions 步驟也能做到。
TestSprite 如何檢查這些慣例
自動產生的測試計畫會針對執行中的服務,涵蓋功能、結構描述、授權、錯誤處理與邊界等類別,其中就包含上述大部分的慣例檢查:每個操作的狀態碼語意、對錯誤輸入的拒絕、資源不存在時的行為,以及分頁筆數是否對得上。
Auto-Authentication 讓工作階段在整趟執行中保持有效,Dynamic Variables 在呼叫之間傳遞數值,Dependency Chains 依每個測試案例所需與所產生的資料推導執行順序,Auto-Cleanup 則只清除這趟執行所建立的資料。最後一項對 REST 的重要性超乎多數人想像,因為冪等性檢查本來就要刻意對同一個破壞性操作呼叫兩次。
你得到的,是自己訂下的慣例在每次變更時都被實際斷言,而不是寫進文件後只能祈禱它成立;這正是防止某個端點在其他端點都回 201 時、偷偷回了 200 的關鍵。
REST 的純粹性對測試重要嗎?
只有在用戶端會依賴它的地方才重要。測試你的服務宣稱遵循的慣例,而不是教科書規定的那一套。
HATEOAS 要怎麼測?
如果你的回應會帶連結,就斷言這些連結能解析,而且指向它們宣稱的位置。如果不會,就略過;真正落實它的服務非常少。
那 GraphQL 呢?
那是完全不同的一套慣例。狀態碼承載的意義少得多,錯誤依設計就放在回應內容裡,因此上述檢查大多無法直接套用。
需要檢查回應標頭嗎?
內容類型一定要檢查。快取和速率限制標頭,則看用戶端會不會依據它們採取行動,這一點值得在斷言之前先弄清楚。
版本管理值得測試嗎?
如果你同時支援一個以上的版本,那就值得。要斷言舊版本的行為仍和過去一致,因為那正是版本號所做出的承諾。