簡體   English   中英

如何使用 Jest 測試調用 API 的函數?

[英]How to test a function that calls an API using Jest?

我是使用 Jest 進行 Node.js 單元測試的新手,並且仍在學習。 我想知道對調用 API 的函數進行單元測試的正確方法是什么? 目前我正在使用交叉提取庫進行 API 調用。 我想實現有效載荷驗證、API 調用上的 2xx 和 5xx API 響應的單元測試。

這是我的代碼:

export const myFunction = (payload: any) => {
  if (_.isNull(payload) || _.isUndefined(payload)) {
    throw new Error('payload is required')
  }

  httpFetch('http://localhost/api/send', { method: 'POST' }, { 'content-type': 'application/json', Authorization: 'Bearer 12ABC'})
    .then((resp) => {
      // ...return 2xx
    })
    .catch((e) => {
       // ...return 5xx
    })
}

有兩種方法可以做到這一點:

模擬或偽造 API 調用並輸出虛假響應(錯誤或其他)


httpFetch = jest.fn(()=>Promise.resolve("provide-dummy-response-payload"));

httpFetch = jest.fn(()=>Promise.reject("provide-dummy-error-payload"));

現在您可以在測試中使用模擬,如下所示:

// pseudo code

  it("makes the api call successfully",async ()=>{
     httpFetch = jest.fn(()=>Promise.resolve("provide-dummy-response-payload"));
     const result = await myFunction("random-payload");
     // make assertions about the result here
  });

  it("fails the api call",async ()=>{
     httpFetch = jest.fn(()=>Promise.reject("provide-dummy-error-payload"));
     const error = await myFunction("random-payload");
     // make assertions about error here
  });

(2)通過故意傳遞正確和不正確的payload並匹配預期結果來進行api調用

在這種情況下,您需要知道如何使 API 調用失敗或通過。

因此,如果有效負載不包含某個道具或者道具的類型不正確,那么您的 API 可能會失敗。

這種方法取決於您提供給函數的有效負載。

從廣義上講,有兩種(非互斥的)方法可以對這樣的函數進行單元測試*:

  1. 隔離測試, 測試替身替換合作者:

     import httpFetch from "wherever"; import myFunction from "somewhere"; jest.mock("wherever"); describe("myFunction", () => { it("calls httpFetch", async () => { httpFetch.mockResolvedValue(); await myFunction({}); expect(httpFetch).toHaveBeenCalledWith( "http://localhost/api/send", { method: "POST" }, { "Content-Type": "application/json", Authorization: "Bearer 12ABC" } ); }); });

    這是“最簡單”的方法,但現在你耦合到了httpFetch接口,這打破了“不要嘲笑你不擁有的東西”的規則——如果該庫的接口在某個時候發生變化,這些測試不會告訴你的。

  2. 集成測試,使用類似Nock 的東西檢查傳輸層發生了什么:

     import nock from "nock"; import myFunction from "somewhere"; describe("myFunction", async () => { it("makes the right request", () => { const scope = nock("http://localhost/api", { reqheaders: { "Content-Type": "application/json", Authorization: "Bearer 12ABC", }, }) .post("/send") .reply(201); await myFunction({}); scope.done(); }); });

    這需要更多的設置,但意味着您與httpFetch接口的耦合較少 - 例如,您可以升級該庫或切換到不同的庫,並且仍然確信一切正常。

還有其他方法可以與特定庫的接口解耦; 例如,您可以圍繞它編寫一個外觀並模擬它。 但是您仍然想知道正在發出正確的請求,並且出於與以前相同的原因,您不應該針對庫的測試替身測試外觀。

您可能還有更高級別的測試,例如針對真實后端的 E2E 測試或針對其存根的合同測試; 這將影響您希望如何平衡較低級別測試的數量和類型。 總的來說,這些選項看起來像:

System:      [Service] -> [Library] -> [HTTP] -> [Backend]

Isolated:    |<----->| -> (Test Double)

Integration: |<------------------>| -> (Nock)

Contract:    |<---------------------------->| -> (Stub)

E2E:         |<----------------------------------------->|

請記住,目標(或其中之一)是確信您正在編寫的代碼有效,並且如果情況不再如此,您會以一種幫助您修復它的方式及時發現。

*關於“單元測試”的確切組成部分,有很多想法。 考慮到速度、獨立性和可並行性的原則,我在此上下文中使用的定義是:實際上並未發出網絡請求的測試。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM