如何在Jest中扩充模拟构造函数的实例

时间:2017-12-05 20:01:18

标签: javascript unit-testing mocking jestjs

我想在Jest单元测试中扩充但不完全替换模拟构造函数的实例。

我想为实例添加一些值,但要保持Jest的自动模拟优势。

例如:

A.js

module.exports = class A {
  constructor(value) {
    this.value = value;
  }
  getValue() {
    return this.value;
  }
}

获得一些自动模拟真棒:

jest.mock('./A');

使用automock,实例有一个模拟.getValue()方法,但它们没有.value属性。

记录在案的way of mocking constructors是:

// SomeClass.js
module.exports = class SomeClass {
  m(a, b) {}
}

// OtherModule.test.js
jest.mock('./SomeClass');  // this happens automatically with automocking
const SomeClass = require('./SomeClass')
const mMock = jest.fn()
SomeClass.mockImplementation(() => {
  return {
    m: mMock
  }
})

const some = new SomeClass()
some.m('a', 'b')
console.log('Calls to m: ', mMock.mock.calls)

将此方法用于A

jest.mock('./A');

const A = require('./A');

A.mockImplementation((value) => {
  return { value };
});

it('does stuff', () => {
  const a = new A();
  console.log(a); // -> A { value: 'value; }
});

关于这一点的好处是,您可以对返回的值执行任何操作,例如初始化.value

缺点是:

  • 你没有免费获得任何自动插件,例如我需要将.getValue()自己添加到实例
  • 您需要为每个创建的实例设置不同的jest.fn()模拟函数,例如:如果我创建两个A实例,则每个实例都需要jest.fn()方法的.getValue()模拟函数
  • SomeClass.mock.instances未填充返回值(GitHub ticket

有一件事没有用(我希望也许Jest做了一些魔术):

A.mockImplementation((value) => {
  const rv = Object.create(A.prototype); // <- these are mocked methods
  rv.value = value;
  return rv;
});

不幸的是,所有实例都使用相同的方法(正如人们所期望的那样,但值得一试)。

我的下一步是通过检查原型来生成模拟(我猜),但我想看看是否有既定的方法。

提前致谢。

2 个答案:

答案 0 :(得分:1)

以下对我有用:

A.mockImplementation(value => {
   const rv = {value: value};
   Object.setPrototypeOf(rv, A.prototype);
   return rv
})

答案 1 :(得分:0)

事实证明,这是固定的(从24.1.0开始),问题中的代码按预期工作。


回顾一下,给定类A

A.js

module.exports = class A {
  constructor(value) {
    this.value = value;
  }
  setValue(value) {
    this.value = value;
  }
}

该测试现在将通过:

A.test.js

jest.mock('./A');

const A = require('./A');

A.mockImplementation((value) => {
  const rv = Object.create(A.prototype); // <- these are mocked methods
  rv.value = value;
  return rv;
});

it('does stuff', () => {
  const a = new A('some-value');
  expect(A.mock.instances.length).toBe(1);
  expect(a instanceof A).toBe(true);
  expect(a).toEqual({ value: 'some-value' });
  a.setValue('another-value');
  expect(a.setValue.mock.calls.length).toBe(1);
  expect(a.setValue.mock.calls[0]).toEqual(['another-value']);
});