首页 > 解决方案 > CommonJS 和 Jest 模拟 - 导出的函数未被模拟

问题描述

我在使用 commonjs 模拟模块中的特定功能时遇到问题

示例模块db.js

function createDefaultProfile(user_id) {
 return { version: 1, username: user_id };
}

function updateOrCreateProfile(user_id, profile) {
  if (profile && profile.credential_id) return null; //no need to update
  if (!profile) profile = createDefaultProfile(user_id);
  if (!profile.credential_id) {
    //update profile with key
  }

module.exports = {createDefaultProfile, updateOrCreateProfile }

示例测试文件尝试 1:

describe("updateOrCreateUser()", () => {
  const db = require('../db.js')

  it("should call createDefaultProfile() when no profile is provided", () => {
    db.createDefaultProfile = jest.fn()
    db.updateOrCreateProfile(userID)
    expect(db.createDefaultProfile).toHaveBeenCalledTimes(1)
  })
})

示例测试文件尝试2:

describe("updateOrCreateUser()", () => {
  jest.mock('../db', () => {
    // Require the original module to not be mocked...
    const originalModule = jest.requireActual('../db');

    return {
      __esModule: true, // Use it when dealing with esModules
      ...originalModule,
      createDefaultProfile: jest.fn().mockReturnValue('arbitrary value'),
    }
  })

  const db = require('../db.js')

  it("should call createDefaultProfile() when no profile is provided", () => {
    db.updateOrCreateProfile(userID)
    expect(db.createDefaultProfile).toHaveBeenCalledTimes(1)
  })
})

两者都返回错误的值,因为永远不会调用模拟模块。在这两种情况下,似乎模拟模块的范围都不正确...

标签: javascripttestingjestjscommonjs

解决方案


createDefaultProfile函数内调用的updateOrCreateProfile函数是原始的,而不是您尝试用jest.fn(). 试试下面:

db.js

function createDefaultProfile(user_id) {
  return { version: 1, username: user_id };
}

function updateOrCreateProfile(user_id, profile) {
  if (profile && profile.credential_id) return null;
  if (!profile) profile = exports.createDefaultProfile(user_id);
  if (!profile.credential_id) {
    console.log('update profile with key');
  }
}

exports.createDefaultProfile = createDefaultProfile;
exports.updateOrCreateProfile = updateOrCreateProfile;

db.test.js

describe('63118259', () => {
  describe('updateOrCreateUser', () => {
    const db = require('./db.js');
    it('should call createDefaultProfile() when no profile is provided', () => {
      const userID = 1;
      const logSpy = jest.spyOn(console, 'log');
      db.createDefaultProfile = jest.fn().mockReturnValueOnce({ credential_id: null });
      db.updateOrCreateProfile(userID);
      expect(db.createDefaultProfile).toHaveBeenCalledTimes(1);
      expect(logSpy).toBeCalledWith('update profile with key');
    });
  });
});

带有覆盖率报告的单元测试结果:

 PASS  stackoverflow/63118259/db.test.js (10.819s)
  63118259
    updateOrCreateUser
      ✓ should call createDefaultProfile() when no profile is provided (26ms)

  console.log
    update profile with key

      at CustomConsole.<anonymous> (node_modules/jest-environment-enzyme/node_modules/jest-mock/build/index.js:866:25)

----------|---------|----------|---------|---------|-------------------
File      | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
----------|---------|----------|---------|---------|-------------------
All files |   77.78 |       50 |      50 |   85.71 |                   
 db.js    |   77.78 |       50 |      50 |   85.71 | 2                 
----------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        12.367s

推荐阅读