提取模拟函数,以便用玩笑更轻松地模拟函数行为

extracting mocked function for easier mocking of function behavior with jest

我将 jest 与 nodejs 一起使用,并为我的模型使用 sequelize。对于我的测试,我想模拟 findAll 的 returned 值来覆盖测试场景。抱歉,如果这是一个非常新手的问题,但我在这个问题上处于死胡同。

init-models.js

module.exports = function initModels(sequelize) {
  //model relationship code here
  ...
  ...
  //end of model relationship code

  return {
    records,
    anotherModel,
    alsoAnotherModel
  };
};

repository.js

const sequelize = require('../sequelize');
const initModels = require('../model/init-models');

let {
  records,
  anotherModel,
  alsoAnotherModel
} = initModels(sequelize);

const fetchRecords = async () => {
  console.info('Fetching records...');
  return await records.findAll({sequelize parameters here});
}

repository.test.js 这会起作用,但需要灵活地模拟 findAll() return value/or throw Error

const repository = require('../../../src/db/repository/repository');
const initModels = require('../../../src/db/model/init-models');

jest.mock('../../../src/db/model/init-models', () => {
    return function() { 
        return {
            records: {
                findAll: jest.fn().mockImplementation(() => [1,2,3])
            }
            //the rest of the code for other models
        }
    }
});

describe('fetchRecords', () => {
    beforeEach(()=> {
    });

    test('should return correct number of records', async () => {
        const result = await repository.fetchRecords();
        expect(result.size).toStrictEqual(3);        //test passed
    });
})

为了允许模拟 findAll 的结果,我尝试提取它以便我可以更改每个测试场景的结果,但它不起作用。我错过了什么?

const mockRecordsFindAll = jest.fn();

jest.mock('../../../src/db/model/init-models', () => {
    return function() { 
        return {
            records: {
                findAll: () => mockRecordsFindAll
            }
            //the rest of the code for other models
        }
    }
});

describe('fetchRecords', () => {
    beforeEach(()=> {
        mockRecordsFindAll.mockReset()
    });

    test('should return correct number of records', async () => {
        mockRecordsFindAll.mockImplementation(() => [1,2,3]); //should expect length 3
        const result = await repository.fetchRecords();
        expect(result.size).toStrictEqual(3);            //fails, findAll was not mocked
    });
})

问题是 mockRecordsFindAll 被返回而不是被执行。 由于@Gid 加工只是返回 mockRecordsFindAll 导致初始化问题(由于提升)。

这种情况的解决方案是使用 decorator pattern 允许 mockRecordsFindAll 之后进行初始化。

const mockRecordsFindAll = jest.fn();

jest.mock('../../../src/db/model/init-models', () => {
    return function() { 
        return {
            records: {
                findAll: function () { 
                   return mockRecordsFindAll.call(this, arguments); 
                }
            }
        }
    }
});

describe('fetchRecords', () => {
    ...
})