添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
# 使用 Mock 撰寫測試(jest.fn, spyOn) 當在撰寫測試,希望專注在撰寫的測試本身(SUT),而不關注該測試的其他依賴函式或套件(DOC)時,就可以透過 Mock 來幫忙實現! - [jest.fn():](https://hackmd.io/HPKnMQMtTs292NULu76JDQ#jestfn) - 模擬一個函式 - 模擬函式回傳的其他方法 - 模擬依賴函式或套件 - [spyOn():](https://hackmd.io/HPKnMQMtTs292NULu76JDQ#spyOn) - 模擬一個函式 - 需帶入兩個參數 ```jsx! jest.spyOn(object, methodName) // 物件名稱, 物件內的方法名稱 👉 jest.fn() 與 spyOn() 的差異: jest.fn() 並不會實際去執行被 mock 的函式,而 spyOn 會去執行傳入的函式。** ### jest.fn() 首先來看一下範例程式碼,我們有兩個函式,其中 `checkRareMagicAttributes` 函式幫我們確認是否為稀有魔法屬性,而 `calculateRareAttributesTotal` 函式幫忙計算總人數,當在執行 `calculateRareAttributesTotal` 函式時是會透過傳入的 `checkRareMagicAttributes` 函式來幫我們確認稀有屬性的人數: ```jsx! const quizList = [ name: "艾草", attributes: "木" name: "Vivian", attributes: "火" name: "啾啾", attributes: "光" // 確認是否為稀有魔法屬性 function checkRareMagicAttributes(attributes) { if (attributes === "光" || attributes === "暗") { return true; } else { return false; // 確認屬性稀有屬性人數 function calculateRareAttributesTotal(data) { let total = 0; data.forEach((item) => { if (checkRareMagicAttributes(item.attributes)) { total += 1; return total; 當針對 `calculateRareAttributesTotal` 撰寫測試而不希望實際去執行 `checkRareMagicAttributes` 函式時,可以透過 **`mock`** 來幫忙實現: 1. 首先透過 jest.fn() 來模擬一個函式: ```jsx test('Introducing mocks', () => { // arrange // 模擬 const mockFunction = jest.fn(); checkRareMagicAttributes = mockFunction; 2. 接著透過 Jest 提供的方法來設定回傳值: - `mockFn.mockReturnValue(value)`:mock 每次的回傳值 - `mockFn.mockReturnValueOnce(value)` :mock 一次回傳值,當沒有設定 `mockReturnValueOnce` 後會回傳 `mockReturnValue` 設定的回傳值 ```jsx test("Introducing mocks", () => { // arrange const mockFunction = jest.fn(); checkRareMagicAttributes = mockFunction; // 設定回傳值 mockFunction.mockReturnValue(false).mockReturnValueOnce(true); 3. 斷言結果:可以透過 calculateRareAttributesTotal 回傳值及 toHaveBeenCalled 來判斷是否有成功呼叫 mockFunction 來斷言。 ```jsx test("Introducing mocks", () => { // arrange const mockFunction = jest.fn(); checkRareMagicAttributes = mockFunction; mockFunction.mockReturnValue(false).mockReturnValueOnce(true); // act const result = calculateRareAttributesTotal(quizList); // assert expect(calculateRareAttributesTotal(quizList)).toBe(1); expect(mockFunction).toHaveBeenCalled(); 像這樣就透過 jest.fn() 的方式成功模擬一個函式! ### 模擬函式回傳的其他方法 **jest.fn()** 除了可以透過 `mockReturnValue` 來模擬回傳值外,還有 `mockImplementation` 方法,可以直接傳入一個模擬函式。 ```jsx // 範例程式碼取自官方文件 const mockFn = jest.fn(scalar => 42 + scalar); mockFn(0); // 42 mockFn(1); // 43 mockFn.mockImplementation(scalar => 36 + scalar); mockFn(2); // 38 mockFn(3); // 39 透過 Jest.fn() 可以更方便模擬依賴函式或套件! const object = { checkRareMagicAttributes: (attributes) => { if (attributes === "光" || attributes === "暗") { return true; } else { return false; // 確認屬性稀有屬性人數 function calculateRareAttributesTotal(data) { let total = 0; data.forEach((item) => { // 透過 checkRareMagicAttributes 的回傳值為 true / false 判斷是否為光暗屬性 if (checkRareMagicAttributes(item.attributes)) { total += 1; return total; 👉 當針對 `calculateRareAttributesTotal` 撰寫測試且希望有去執行 `checkRareMagicAttributes` 函式時,可以透過 `spyOn` 來幫忙實現: 1. 首先透過 `spyOn`,並帶入物件名稱及方法名稱 `checkRareMagicAttributes`: ```jsx test("Introducing spyOn", () => { // arrange const spyOnFunction = jest.spyOn(object,"checkRareMagicAttributes"); 2. 接著透過 result 來執行行動 ```jsx test("Introducing spyOn", () => { // arrange const spyOnFunction = jest.spyOn(object,"checkRareMagicAttributes"); // act const result = calculateRareAttributesTotal(quizList); 3. 斷言結果:可以透過 `calculateRareAttributesTotal` 回傳值及 `toHaveBeenCalledTimes` 來判斷是否有成功呼叫 `spyOnFunction` 來斷言,這邊因為資料有三筆物件,所以共呼叫了三次 `spyOnFunction`。 ```jsx! test("Introducing spyOn", () => { // arrange const spyOnFunction = jest.spyOn(object,"checkRareMagicAttributes"); // act const result = calculateRareAttributesTotal(quizList); // assert expect(result).toBe(1); expect(spyOnFunction).toHaveBeenCalledTimes(3); 像這樣就透過 spyOn 模擬成功! #### 可用 mockRestore() 恢復原始函式 `spyOn` 也可以使用 `mock` 的方法如 `mockImplementation` 等模擬回傳函式,而當想調用原始函式而不掉用模擬函式時 `spyOn` 還可以使用 `mockRestore()`` 的方式將模擬的函式改回原本函式,可用於多個測試其中一項須改回原本函式時。 https://jestjs.io/zh-Hans/docs/mock-functions https://jestjs.io/docs/mock-function-api https://medium.com/enjoy-life-enjoy-coding/jest-jojo是你-我的替身能力是-mock-4de73596ea6e https://blog.jimmydc.com/mock-asynchronous-functions-with-jest/ https://vhudyma-blog.eu/3-ways-to-mock-axios-in-jest/ https://www.youtube.com/watch?v=1Xafx6o82Aw&ab_channel=SoftwareTestingHelp https://dwatow.github.io/2020/04-24-jest/jest-doc-5/ https://jestjs.io/docs/jest-object#jestspyonobject-methodname https://medium.com/enjoy-life-enjoy-coding/jest-jojo是你-我的替身能力是-mock-4de73596ea6e https://www.youtube.com/watch?v=1Xafx6o82Aw&ab_channel=SoftwareTestingHelp https://dwatow.github.io/2020/04-24-jest/jest-doc-5/