如何使用 Jest 监视方法调用?

Posted

技术标签:

【中文标题】如何使用 Jest 监视方法调用?【英文标题】:How can I use Jest to spy on a method call? 【发布时间】:2017-08-31 21:15:12 【问题描述】:

我最近想测试一些自定义方法是否在 React 组件的 componentDidMount 方法中被有条件地调用。

componentDidMount() 
  if (this.props.initOpen) 
    this.methodName();
  

我使用 Jest 作为我的测试框架,其中包括用于模拟/间谍的 jest.fn()。我已经读到,通过执行以下操作,使用 Sinon 进行测试是相当简单的:

sinon.spy(Component.prototype, "methodName");
const wrapper = mount(<Component ...props />);
expect(wrapper.instance().methodName).toHaveBeenCalled();

我正在尝试像这样用 Jest 重新创建它:

Component.prototype.methodName = jest.fn();
const wrapper = mount(<Component ...props />);
expect(wrapper.instance().methodName).toHaveBeenCalled();

此代码失败并抛出以下错误:

jest.fn() value must be a mock function or spy.
Received:
  function: [Function bound mockConstructor]

是否可以使用 Jest 测试此功能?如果有,怎么做?

【问题讨论】:

【参考方案1】:

关键是在对象的prototype 上使用笑话spyOn 方法。应该是这样的:

const spy = jest.spyOn(Component.prototype, 'methodName');
const wrapper = mount(<Component ...props />);
wrapper.instance().methodName();
expect(spy).toHaveBeenCalled();

如在此处找到,例如:Test if function is called react and enzyme

请注意 最好在每次测试运行后清除间谍功能

let spy

afterEach(() => 
  spy.mockClear()
)

https://facebook.github.io/jest/docs/en/jest-object.html#jestclearallmocks

【讨论】:

谢谢!看起来这只是几个月前在 19.0.0 中发布的。不敢相信我在文档中跳过了它。 它会真正调用组件中的methodName() 函数还是只是伪造它? 来自文档:“注意:默认情况下,jest.spyOn 也调用了 spy 方法。” facebook.github.io/jest/docs/en/… 如果&lt;Component ...props /&gt;&lt;Provider&gt; 包裹怎么办,这会起作用吗?我收到了Cannot read property '_isMockFunction' of undefined'。不知道是不是因为上面的原因。 对我来说,您似乎在监视一种不存在的方法,这就是您获得 Cannot read property '_isMockFunction' of undefined' 的原因。【参考方案2】:

我知道它有点晚了,但我遇到了这个问题并建议测试componentDidMount 启动对嵌套方法的调用,你的测试应该看起来像这样:

模块

componentDidMount() 
  if (this.props.initOpen) 
    this.methodName();
  

测试 - 良好

it('should call methodName during componentDidMount', () => 
    const methodNameFake = jest.spyOn(MyComponent.prototype, 'methodName');
    const wrapper = mount(<MyComponent ...props />);
    expect(methodNameFake).toHaveBeenCalledTimes(1);
);

如果您调用componentDidMount,那么通过componentDidMount 调用methodName 的断言更有效。

测试 - 不好

it('should call methodName during componentDidMount', () => 
    const spy = jest.spyOn(Component.prototype, 'methodName');
    const wrapper = mount(<Component ...props />);
    wrapper.instance().methodName();
    expect(spy).toHaveBeenCalled();

通过这样编写测试 - 您调用该方法,然后断言它已被调用。它当然会给你刚才调用它。

【讨论】:

这些测试都不适合我,根本无法通过 您是否传递了组件所需的所有道具? 终于让它工作了,需要为它创建一个实例并在我的间谍上强制更新。【参考方案3】:

如果您尝试测试在 componentDidMount 上调用的 public 方法(如果您使用的是 TypeScript),则需要显式调用 instancecomponentDidMount 方法调用,因为直到组件实例化后才定义公共方法。

要测试这样的东西:

代码

public componentDidMount() 
  if (this.props.initOpen) 
    this.methodName();
  


public methodName = () => 
  // some code here

测试

it('should call methodName during componentDidMount', () => 
  const wrapper = mount(<MyComponent ...props />);
  const instance = wrapper.instance();
  jest.spyOn(instance, 'methodName')
  expect(instance.methodName).toHaveBeenCalled();
);

【讨论】:

【参考方案4】:
const toastMethodSpy = jest.spyOn(sharedMockedOTPComponent, 'toast')
sharedMockedOTPComponent.handleResendOtpFailure(networkError)

//hide loader
expect(sharedMockedOTPComponent.state.showLoader).toBe(false)
//error message in toast should have been shown
expect(toastMethodSpy).toHaveBeenCalledTimes(1)

【讨论】:

以上是关于如何使用 Jest 监视方法调用?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Jest 监视默认导出函数?

如何模拟 ES6 超类并用 jest.js 监视它?

如何使用 jest.spyOn 测试 RTKQuery 端点

如何使用 Jest 在 NestJS 的提供者中模拟和监视“mongoose.connect”

开玩笑 - 使用 spyOn 函数时,确保不调用被监视的函数

监视在 Jest 中调用另一个函数的导入函数