簡體   English   中英

開玩笑地從另一個文件中模擬嵌套的 function

[英]Jest mock nested function from another file

我正在學習 NodeJs 和 Jest。 我在進行單元測試時遇到了麻煩。 我只是將我的實際代碼翻譯成一個簡單的邏輯。 我有兩個文件如下。

// age.js
function getAge(birthYear) {
    const age = 2021-birthYear;
    return age
}

module.exports = { getAge }
// user.js
const { getAge } = require("./age");

async function isMinor(){
    const bYear = 1991
    const age = await getAge(bYear)
    if( age <= 18) {
        return true
    }
    return false
}

module.exports = { isMinor }

isMinor從另一個文件調用getAge ,我想測試isMinor而不實際調用getAge 我參考了這篇文章並寫了我的測試,但我仍然遇到了一些問題。

// user.test.js
const { isMinor } = require("./user")

describe("Age Test", () => {

    // Question 1: how can I properly import getAge function here and mock a return value for it? I also tried mockImplementation and mockReturnedValue, but they didn't work
    // I don't want to actually invoke getAge function
    beforeEach(() => {
        jest.mock("./age", () => ({
            getAge: () => 99,
        }))
    })

    // Question 2: How can I teardown the moch after the test 
    afterEach(() =>{
        getAge.mockRestore()
    })

    test("should be an adult", async () => {
        const isMinor = await isMinor();
        expect(isMinor).toEqual(false);
    });
});

我希望從getAge收到 99 ,但它返回null 我很感激任何幫助。 謝謝你。

下面的示例使用"jest": "^26.6.3"

user.js

const { getAge } = require('./age');

async function isMinor() {
  const bYear = 1991;
  const age = await getAge(bYear);
  console.log('age: ', age);
  if (age <= 18) {
    return true;
  }
  return false;
}

module.exports = { isMinor };

選項 1 :在beforeEach鈎子功能 scope 中使用jest.mock() ,它不會被提升到代碼的頂部。 所以你需要通過jest.mock()方法在 mocking 之后需要模塊。

describe('Age Test', () => {
  beforeEach(() => {
    jest.mock('./age', () => ({
      getAge: jest.fn(() => 99),
    }));
  });

  test('should be an adult', async () => {
    const { isMinor } = require('./user');
    const { getAge } = require('./age');
    const actual = await isMinor();
    expect(actual).toBeFalsy();
    expect(getAge).toBeCalledWith(1991);
  });
});

單元測試結果:

 PASS  examples/66288290/user.test.js
  Age Test
    ✓ should be an adult (1911 ms)

  console.log
    age:  99

      at examples/66288290/user.js:6:11

----------|---------|----------|---------|---------|-------------------
File      | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
----------|---------|----------|---------|---------|-------------------
All files |    87.5 |       50 |     100 |    87.5 |                   
 user.js  |    87.5 |       50 |     100 |    87.5 | 8                 
----------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        3.197 s

選項 2 :在模塊 scope 中使用jest.mock() ,它將被提升到代碼的頂部。 即使您require文件頂部的模塊。 您需要的./age模塊已經被模擬了。

const { isMinor } = require('./user');
const { getAge } = require('./age');

jest.mock('./age', () => ({
  getAge: jest.fn(() => 99),
}));

describe('Age Test', () => {
  afterAll(() => {
    jest.resetAllMocks();
  });

  test('should be an adult', async () => {
    const actual = await isMinor();
    expect(actual).toBeFalsy();
    expect(getAge).toBeCalledWith(1991);
  });
});

單元測試結果:

 PASS  examples/66288290/user.test.js
  Age Test
    ✓ should be an adult (11 ms)

  console.log
    age:  99

      at examples/66288290/user.js:6:11

----------|---------|----------|---------|---------|-------------------
File      | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
----------|---------|----------|---------|---------|-------------------
All files |    87.5 |       50 |     100 |    87.5 |                   
 user.js  |    87.5 |       50 |     100 |    87.5 | 8                 
----------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        3.502 s

由於您僅使用模擬值測試isMinor ,因此您需要使用多個值對其進行測試以涵蓋所有不同的場景(分支),因此您只需調用一次即可為./age.js創建一次模擬:

const { getAge } = require('./age');
jest.mock('./age');

它將為每個模塊 function 生成一個模擬 function 僅用於此測試文件

使用 jest.mock 模擬的模塊僅對調用 jest.mock 的文件進行模擬。 另一個導入模塊的文件將獲得原始實現,即使它在模擬模塊的測試文件之后運行。

因此,您無需恢復原始實現。

使用自動模擬的最大優勢是當實現中的方法(在本例中為getAge )被刪除時 - 測試將失敗。

剩下要做的就是設置要測試的模擬的返回值。 並且由於預計會返回 promise 您應該使用.mockResolvedValue()

user.test.js
const { isMinor } = require("./user");
const { getAge } = require('./age');

jest.mock('./age');

describe("Age Test", () => {
  describe('getAge returning more than 18', () => {
    beforeAll(() => {
      getAge.mockResolvedValue(99)
    })

    test("should be an adult", async () => {
      expect(await isMinor()).toEqual(false);
    });
  })

  describe('getAge returning less than 18', () => {
    beforeAll(() => {
      getAge.mockResolvedValue(13)
    })

    test("should be a minor", async () => {
      expect(await isMinor()).toEqual(true);
    });
  })
});

工作示例

暫無
暫無

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

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