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 呢?

那是完全不同的一套慣例。狀態碼承載的意義少得多,錯誤依設計就放在回應內容裡,因此上述檢查大多無法直接套用。

需要檢查回應標頭嗎?

內容類型一定要檢查。快取和速率限制標頭,則看用戶端會不會依據它們採取行動,這一點值得在斷言之前先弄清楚。

版本管理值得測試嗎?

如果你同時支援一個以上的版本,那就值得。要斷言舊版本的行為仍和過去一致,因為那正是版本號所做出的承諾。

重點摘要

測試你的 API 所做出的承諾。

REST API 測試應該驗證你的服務所宣稱的慣例:狀態碼語意、冪等性、分頁總數,以及無法辨識的篩選條件會不會被拒絕。而支撐這一切的,是對回應內容而非狀態碼做斷言。