【问题标题】:How can I use Jest to spy on a method call?如何使用 Jest 监视方法调用?
【发布时间】: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 测试此功能?如果有,怎么做?

【问题讨论】:

    标签: javascript reactjs testing jestjs enzyme


    【解决方案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)
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-11-12
        • 1970-01-01
        • 2019-06-12
        • 2013-08-31
        • 2014-04-30
        相关资源
        最近更新 更多