Node.js 来自另一个文件的Jest模拟嵌套函数

Node.js 来自另一个文件的Jest模拟嵌套函数,node.js,unit-testing,jestjs,mocking,Node.js,Unit Testing,Jestjs,Mocking,我正在学习点头和开玩笑。我在单元测试方面遇到了问题。我只是把我的实际代码翻译成一个简单的逻辑。我有两个文件如下 // age.js function getAge(birthYear) { const age = 2021-birthYear; return age } module.exports = { getAge } 我希望从getAge接收99,但它返回null。谢谢你的帮助。谢谢。下面的示例使用的“笑话”:“^26.6.3” user.js: const{getA

我正在学习点头和开玩笑。我在单元测试方面遇到了问题。我只是把我的实际代码翻译成一个简单的逻辑。我有两个文件如下

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

module.exports = { getAge }
我希望从
getAge
接收99,但它返回
null
。谢谢你的帮助。谢谢。

下面的示例使用
的“笑话”:“^26.6.3”

user.js

const{getAge}=require('./age');
异步函数isMinor(){
const bYear=1991;
const age=等待获取(bYear);
console.log('age:',age);
如果(年龄){
在每个之前(()=>{
开玩笑('./年龄',()=>({
getAge:jest.fn(()=>99),
}));
});
测试('应该是成年人',异步()=>{
const{isMinor}=require('./user');
const{getAge}=require('./age');
const actual=wait isMinor();
expect(实际).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
 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
选项2:在模块作用域中使用
jest.mock()
,它将被提升到代码顶部。即使您
需要文件顶部的模块。您需要的
/age
模块已经被模拟

const{isMinor}=require('./user');
const{getAge}=require('./age');
开玩笑('./年龄',()=>({
getAge:jest.fn(()=>99),
}));
描述('年龄测试',()=>{
毕竟(()=>{
jest.resetAllMocks();
});
测试('应该是成年人',异步()=>{
const actual=wait isMinor();
expect(实际).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
 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
下面的示例使用了
“jest”:“^26.6.3”

user.js

const{getAge}=require('./age');
异步函数isMinor(){
const bYear=1991;
const age=等待获取(bYear);
console.log('age:',age);
如果(年龄){
在每个之前(()=>{
开玩笑('./年龄',()=>({
getAge:jest.fn(()=>99),
}));
});
测试('应该是成年人',异步()=>{
const{isMinor}=require('./user');
const{getAge}=require('./age');
const actual=wait isMinor();
expect(实际).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
 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
选项2:在模块作用域中使用
jest.mock()
,它将被提升到代码顶部。即使您
需要文件顶部的模块。您需要的
/age
模块已经被模拟

const{isMinor}=require('./user');
const{getAge}=require('./age');
开玩笑('./年龄',()=>({
getAge:jest.fn(()=>99),
}));
描述('年龄测试',()=>{
毕竟(()=>{
jest.resetAllMocks();
});
测试('应该是成年人',异步()=>{
const actual=wait isMinor();
expect(实际).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
 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');
它将仅为此测试文件为每个模块函数生成一个模拟函数

使用jest.mock模拟的模块仅针对调用jest.mock的文件进行模拟。导入该模块的另一个文件将获得原始实现,即使它在模拟该模块的测试文件之后运行

因此,您无需恢复原始实现

使用自动模拟的最大好处是当来自实现的方法(在本例中为
getAge
)被删除时,测试将失败。

剩下要做的唯一一件事就是设置你想要测试的mock的返回值,因为它应该返回你应该使用的承诺

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);
    });
  })
});

由于您只使用模拟值测试
isMinor
,因此您需要使用多个值来测试它,以覆盖所有不同的场景(分支),因此只需调用以下命令即可为
/age.js
创建一次模拟:

const { getAge } = require('./age');
jest.mock('./age');
它将仅为此测试文件为每个模块函数生成一个模拟函数

使用jest.mock模拟的模块仅针对调用jest.mock的文件进行模拟。导入该模块的另一个文件将获得原始实现,即使它在模拟该模块的测试文件之后运行

因此,您无需恢复原始实现

使用自动模拟的最大好处是当来自实现的方法(在本例中为
getAge
)被删除时,测试将失败。

剩下要做的唯一一件事就是设置你想要测试的mock的返回值,因为它应该返回你应该使用的承诺

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);
    });
  })
});

我认为在每个之前都应该有resetModules。选项1可以工作,因为它只导入了一次。Hi@slideshowp2。只是一个后续问题:如果
getAge
isMinor
在同一个文件中会怎么样?只有当我
const{isMinor,getAge}=require(“./文件”)时,如何才能模拟getAge
?非常感谢much@Luke然后您需要执行
jest.mock('./文件')
模拟
/file
模块我认为每个模块之前都应该有resetModules。选项1可以工作,因为它只导入了一次。Hi@slideshowp2。只是一个后续问题:如果
getAge
isMinor
在同一个文件中怎么办?只有当我
常量{isMinor,getAge}=require(“./file”)时,怎么才能模拟getAge
?非常感谢much@Luke然后您需要执行
jest.mock('./file')
以模拟
/file
模块