如何用 jest 解开单个实例方法

Posted

技术标签:

【中文标题】如何用 jest 解开单个实例方法【英文标题】:how to unmock a single instance method with jest 【发布时间】:2019-06-04 04:51:59 【问题描述】:

来自 rspec,我无法理解玩笑的嘲弄。我正在尝试的方法是自动模拟一个类的构造函数及其所有函数,然后一一解开它们以仅测试一个函数。我能在上面找到的唯一文档是使用 2 个类,模拟 1 个类,然后测试这些函数是从另一个未模拟的类中调用的。

下面是我想要做的一个基本的、人为的想法。有人可以指导我这样做吗?

foo.js

class Foo
  constructor: ->
    this.bar()
    this.baz()
  bar: ->
    return 'bar'
  baz: ->
    return 'baz'

foo_test.js

// require the class
Foo = require('foo')

// mock entire Foo class methods
jest.mock('foo')

// unmock just the bar method
jest.unmock(Foo::bar)

// or by
Foo::bar.mockRestore()

// and should now be able to call
foo = new Foo
foo.bar() // 'bar'
foo.baz() // undefined (still mocked)

// i even tried unmocking the instance
foo = new Foo
jest.unmock(foo.bar)
foo.bar.mockRestore()

【问题讨论】:

【参考方案1】:

mockFn.mockRestore()jest@24.9.0 一起为我工作:

// Create a spy with a mock
const consoleInfoSpy = jest.spyOn(console, 'info').mockImplementation(() => )

// Run test or whatever code which uses console.info
console.info('This bypasses the real console.info')

// Restore original console.info
consoleInfoSpy.mockRestore()

【讨论】:

【参考方案2】:

这并不严格适用于 OP,但寻求答案的人可能会在这里结束。您可以像这样模拟一个模块,除了某些部分之外的所有测试

模拟/saladMaker.js

// Let Jest create the mock.
const saladMaker = jest.genMockFromModule('../saladMaker');

// Get the unmocked chop method.
const chop = require.requireActual('../saladMaker');

// Patch it in.
saladMaker.chop = chop;

module.exports = saladMaker;

关键部分是使用requireActual 来获取未模拟的模块。

bypassing module mocks

更新

require.requireActualhas been replaced 和jest.requireActual

【讨论】:

jest.genMockFromModule() 已弃用,因此我们可以使用 jest.createMockFromModule()【参考方案3】:

在 Jest 中模拟后无法获取原始模块。 jest.mock 所做的是用你的模拟替换模块。

所以即使你写:

Foo = require('foo')
jest.mock('foo')

Jest 会将jest.mock('foo') 调用提升到调用堆栈的顶部,因此这是测试开始时发生的第一件事。这也会影响您导入的所有其他模块以及导入 foo.js

您可以尝试使用spyOn 来监视对象的函数,也应该与类一起使用,但我不太确定。

【讨论】:

是的,我也一直在玩,但是遇到了同样的问题。我也在考虑尝试模拟构造函数,但似乎也无法弄清楚。莫名其妙地在做这件事,但是查看他们的源代码可能比我自己弄清楚要花更长的时间【参考方案4】:

我尝试了很多东西,但最终对我有用的是(使用 Create React App):

setupTests.ts

jest.mock("./services/translations/translationsService", () => (
  __esModule: true,
  default: 
    initDict: (): void => undefined,
    translate: (key: Phrases): string => key,
  ,
  t: (key: Phrases): string => key,
));

模拟所有测试的模块。为了取消模拟单个测试套件,我做了:

jest.mock("../../../services/translations/translationsService", () =>
  jest.requireActual("../../../services/translations/translationsService")
);

describe(() =>  /* test suite goes here and uses real implementation */ );

【讨论】:

【参考方案5】:

Jest@27.4.7

const mockChildComponent = jest.mock('../../../src/components/common/childComponent', () => (
  __esModule: true,
  default: (props: Prop) => (
    <div data-test-id="stub-chart-panel">
      props.label
    </div>
  ),
));

test('mock child', async () => 
  const wrapper = mount(
      <ParentComponent />
  );
  expect(....);
);

mockChildComponent.restoreAllMocks();

test('default child component ', async () => 
  const wrapper = mount(
      <ParentComponent />
  );
  expect(....);
);

【讨论】:

以上是关于如何用 jest 解开单个实例方法的主要内容,如果未能解决你的问题,请参考以下文章

如何用 swig 实例化模板类的模板方法?

iOS,如何用 animateWithDuration 替换简单的 UIView 图形实例?

如何用子类内部状态包装所有 python 超类方法?

mysql mysqldump如何用

如何用Elasticsearch实现类似SQL中的IN查询实例

用 Jest 重置单个模块