【问题标题】:Jest mock class method on a test-by-test basis在逐个测试的基础上开玩笑模拟类方法
【发布时间】:2019-03-15 20:31:02
【问题描述】:

我正在尝试使用返回 JSON 的方法来模拟一个实用程序库类。

实际的库结构

module.exports = class Common() {
  getConfig() {
  return {
    real: 'data'
  }
}

被测文件如下:


const Common = require('./common');
const common = new Common();
const config = common.getConfig();

...

const someFunction = function() {
  // config.real is used inside this function
}

我正在尝试模拟 Common 类并为每个 Jest 测试返回不同的配置 JSON。

const fileUnderTest = require('./../fileUnderTest.js');
const Common = require('./../common.js');
jest.mock('./../common.js');

describe('something', () => {
  it('test one', () => {
    Common.getConfig = jest.fn().mockImplementation(() => {
      return {
        real : 'fake' // This should be returned for test one
      };
    });

    fileUnderTest.someFunction(); //config.real is undefined at this point
  });

  it('test two', () => {
  Common.getConfig = jest.fn().mockImplementation(() => {
      return {
        real : 'fake2' // This should be returned for test two
      };
    });
  })
})

是否可以从测试文件顶部common.js的自动模拟创建的模拟类方法中设置返回值?

我尝试过使用mockReturnValueOnce() 等。

【问题讨论】:

    标签: javascript unit-testing mocking jestjs


    【解决方案1】:

    jest.mock

    在这种情况下,您实际上不需要自动模拟整个 common 模块,因为您只是替换了一种方法的实现,因此不需要 jest.mock('./../common');

    Common.getConfig

    getConfig 是一个prototype method,所以getConfig 存在于Common原型 上。要模拟它,请使用 Common.prototype.getConfig 而不是 Common.getConfig

    config in fileUnderTest.js

    Common 的一个实例被创建,config 被设置为调用common.getConfig() 的结果只要fileUnderTest 运行,它就会发生必需,所以Common.prototype.getConfig 的模拟必须在之前你调用require('./../fileUnderTest')


    const Common = require('./../common');
    Common.prototype.getConfig = jest.fn().mockImplementation(() => ({ real: 'fake' }));
    const fileUnderTest = require('./../fileUnderTest');
    
    describe('something', () => {
      it('should test something', () => {
        fileUnderTest.someFunction();  // config.real is 'fake' at this point
      });
    });
    

    更新

    要以不同方式模拟config.real对于每个测试这样的代码需要测试之间的modules be reset

    describe('something', () => {
      afterEach(() => {
        jest.resetModules();  // reset modules after each test
      })
    
      it('test one', () => {
        const Common = require('./../common');
        Common.prototype.getConfig = jest.fn().mockImplementation(() => ({ real: 'fake' }));
        const fileUnderTest = require('./../fileUnderTest');
        fileUnderTest.someFunction();  // config.real is 'fake'
      });
    
      it('test two', () => {
        const Common = require('./../common');    
        Common.prototype.getConfig = jest.fn().mockImplementation(() => ({ real: 'fake2' }));
        const fileUnderTest = require('./../fileUnderTest');
        fileUnderTest.someFunction();  // config.real is 'fake2'
      })
    })
    

    重置模块是必要的,因为一旦需要一个模块,它就会被添加到模块缓存中,并且每次需要它时都会返回相同的模块,除非模块被重置。

    【讨论】:

    • 我想我不清楚这个问题,抱歉。我需要为每个it 返回与原型方法不同的东西。我已经编辑了这个问题,试图让它更清楚。
    • 啊,太棒了!我认为 Jest 有时需要稍微重新思考一下,以在 it 块内包含所有需要的需求等!不过,目前感觉有点笨拙。
    猜你喜欢
    • 2021-06-16
    • 2021-03-31
    • 2017-03-14
    • 2017-11-19
    • 2019-03-23
    • 1970-01-01
    • 2019-12-21
    • 2018-10-29
    相关资源
    最近更新 更多