[英]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
})
}
有兩種方法可以做到這一點:
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
});
在這種情況下,您需要知道如何使 API 調用失敗或通過。
因此,如果有效負載不包含某個道具或者道具的類型不正確,那么您的 API 可能會失敗。
這種方法取決於您提供給函數的有效負載。
從廣義上講,有兩種(非互斥的)方法可以對這樣的函數進行單元測試*:
隔離測試, 測試替身替換合作者:
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
接口,這打破了“不要嘲笑你不擁有的東西”的規則——如果該庫的接口在某個時候發生變化,這些測試不會告訴你的。
集成測試,使用類似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.