當你的程式碼呼叫 API 時,你需要一種方法來測試它,而不必等到真實 API 故障時才測試。 你有五種替代項目可以選擇。 人們對這些名稱的使用很寬鬆,以下說明本文如何使用這些名稱:
- Stub:一個用於取代你的 HTTP 用戶端或 SDK 呼叫的行程內替身,回傳一個預設的答案。 它快速且可重複,並且測試你用來寫出該回應的邏輯。
- Mock:一個也會記錄你的程式碼如何呼叫它的存根,讓你的測試能檢查呼叫內容。 它甚至延伸到一個存根。
- 假伺服器:一個小型且運作中的伺服器,通常存在記憶體中,你的應用程式透過 HTTP 呼叫它,而非真實 API。 它會測試你的 HTTP 用戶端,但你必須將應用程式指向它的 URL。
- 模擬器:服務的本地版本,通常由服務擁有者發布,對所支援的操作其行為類似真實服務。 在依賴它處理錯誤前,先確認它涵蓋哪些限制和故障。
- 攔截代理:位於你的應用程式與 API 之間的網路上。 你的應用程式呼叫真實的 URL,代理伺服器會透過你定義的回應傳遞請求或回應部分請求。 你的應用程式必須透過代理伺服器傳送流量,並且在 HTTPS 上,信任代理的憑證。
如何測試呼叫 API 的程式碼
| Approach | 它測試什麼 | 它需要的內容 | 就在 |
|---|---|---|---|
| 存根或模擬 | 你針對特定回應的邏輯 | 你的測試框架 | 你在單元測試中測試商業邏輯、解析和錯誤分支 |
| 假伺服器 | 你的 HTTP 用戶端與序列化功能 | 在你的應用程式中設定基礎 URL 或設定開關 | API 還不存在,或者你需要穩定的後端來做 UI 工作 |
| Emulator | 支援的操作其行為接近真實服務 | 不同的端點或 連接字串 | 服務的擁有者會提供一個,你則離線開發 |
| 使用測試帳號的 Real API | 真正的東西 | 憑證、配額與資金 | 你要從頭到尾驗證主路徑 |
| 攔截 Proxy | 在真實 URL 上執行的應用程式,包含 SDK 重試與回應標頭 | 代理設定與憑證信任 | 你測試失敗、限制和延遲,卻不改變應用程式 |
你需要這些中的一個以上。 存根能讓你的單元測試執行更快。 代理會告訴你當真實 API 出錯時,整個應用程式會做什麼。 想了解更多兩者如何結合,請參考 Dev Proxy 與單元測試的比較。
程式碼代理可建構的內容
當你要求程式設計代理讓你的應用程式能處理 API 呼叫失敗的情況,並展示它確實能運作時,它會替你選擇一個替代方案。 我們想知道是哪一個,所以用三個程式碼代理做了測試(210 次)。 這些任務用了像是「正確處理速率限制並證明它有效」、「在不花錢做真實 API 呼叫的情況下驗證」以及「在沒有 OpenAI 金鑰或網路連線的情況下執行」等說法。
- 在 140 次要求可運作程式碼的執行中,有 76% 是代理程式手動建構出失敗情境:fetch 存根、
httpx.MockTransport,或臨時的 HTTP 伺服器。 - 在 105 次執行中,有 61 次是針對會呼叫 GitHub、OpenAI 或天氣 API 的應用程式,代理會為應用程式新增基礎網址或設定切換器,以便能連到其偽造的服務。
- 在真實 API 可用且提示未排除使用它的 75 次執行中,測試該應用程式的真實 API URL 的次數為 0。
存根是單元測試的合理選擇。 空白是他們省略的部分。代理的存根函式回傳的是代理預期的錯誤,但可能與 API 傳送的錯誤不符。 還有它新增的開關,用來透過你的應用程式存取假船。
如何使用代理程式的測試項目
- 保留用於你的邏輯的 stub 程式。 它們很快,還會測試代理程式寫的分支。
- 請要求提供實際的錯誤格式。 請代理程式以提供者記錄的狀態碼、標頭和主體欄位為依據來模擬每個錯誤。 單純的 429 無法測試你的應用程式是否讀取
retry-after,或區分計費錯誤與速率限制。 - 審查切換為測試新增。 如果代理程式只為了測試能找到假網址而新增基礎 URL 設定,請決定是否要將該設定納入你的生產程式碼。
- 在真實網址上執行一次應用程式,並模擬失敗情況。 在你發布前,先檢查執行中的應用程式、SDK 以及重試政策如何處理 API 本身的錯誤。 要逐步檢視代理的錯誤處理,請參閱 如何驗證您的程式碼代理所撰寫的錯誤處理。
在你的應用程式中試試看
Dev Proxy 是一種用於開發的攔截式 Proxy。 它會回傳你為應用程式已呼叫的 URL 所定義的回應,且不會更改應用程式的程式碼。 在你的設定中啟用 MockResponsePlugin, devproxyrc.json:
{
"$schema": "https://raw.githubusercontent.com/dotnet/dev-proxy/main/schemas/v3.3.1/rc.schema.json",
"plugins": [
{
"name": "MockResponsePlugin",
"enabled": true,
"pluginPath": "~appFolder/plugins/DevProxy.Plugins.dll",
"configSection": "mocksPlugin"
}
],
"urlsToWatch": [
"https://api.contoso.com/*"
],
"mocksPlugin": {
"$schema": "https://raw.githubusercontent.com/dotnet/dev-proxy/main/schemas/v3.3.1/mockresponseplugin.schema.json",
"mocksFile": "mocks.json"
}
}
接著在 mocks.json 中定義回應。 這個會回傳 503 預測端點的 Retry-After 標頭:
{
"$schema": "https://raw.githubusercontent.com/dotnet/dev-proxy/main/schemas/v3.3.1/mockresponseplugin.mocksfile.schema.json",
"mocks": [
{
"request": {
"url": "https://api.contoso.com/v1/forecast*",
"method": "GET"
},
"response": {
"statusCode": 503,
"headers": [
{
"name": "Retry-After",
"value": "10"
}
],
"body": {
"error": "Service unavailable"
}
}
}
]
}
啟動 Dev Proxy,並照常執行你的應用程式:
devproxy --config-file devproxyrc.json
與模擬不符的請求會送往真正的 API。 當你需要一個還不存在的後端時,CrudApiPlugin 會用記憶體資料 模擬 CRUD API 。 若想隨機讓部分請求失敗,而不是每次都失敗,請參考 「使用隨機錯誤測試我的應用程式」。 要安裝 Dev Proxy,請參見 設定 Dev Proxy。