如何使用spyOn测试异步功能? [英] How to test async function with spyOn?

查看:93
本文介绍了如何使用spyOn测试异步功能?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在React Native应用中测试异步功能.

I am trying to test an async function in a react native app.

class myClass extends React.Component {

  ...

  closeModal = async () => {

    if (someCondition) {
      await myFunction1();
    } else {
      await myFunction2();
    }

    this.props.navigation.state.params.onGoBack();
    this.props.navigation.navigate('Main');
  };

  ...

}

这是我的测试

const navigation = {
  navigate: jest.fn(),
  state: { params: { onGoBack: jest.fn() } },
};

const renderComponent = overrides => {
  props = {
    navigation,
    ...overrides,
  };

  return shallow(< myClass.wrappedComponent {...props} />);
};


describe('When the user presses the close icon', () => {
    it('should close the modal', () => {
      const wrapper = renderComponent();
      const instance = wrapper.instance();
      const spyCloseModal = jest.spyOn(instance, 'closeModal');
      instance().forceUpdate();
      component
        .find({ testID: 'close-icon' })
        .props()
        .onPress();
      expect(spyCloseModal).toHaveBeenCalled(); // this is passed
      expect(navigation.navigate).toHaveBeenCalled(); // this is not passed
    });
});

似乎卡在了await调用中.如果我删除了等待呼叫,那么它将过去.有人在另一篇文章中提到在spyOn之后使用.and.callThrough,但它给了我这个错误

It looks like it gets stuck on the await calls. If I remove the await calls then it passes. Someone mentioned in another post to use .and.callThrough after spyOn but it gives me this error

无法读取未定义的属性"callThrough"

Cannot read property 'callThrough' of undefined

推荐答案

解决方案之一是进行测试async并运行await (anything)将测试拆分为多个微任务:

one of solution is to make your test async and run await (anything) to split your test into several microtasks:

it('should close the modal', async () => {
      const wrapper = renderComponent();
      component
        .find({ testID: 'close-icon' })
        .props()
        .onPress();
      await Promise.resolve();
      expect(navigation.state.params.onGoBack).toHaveBeenCalled(); 
      expect(navigation.navigate).toHaveBeenCalledWith("Main");
    });

我相信您不需要实例方法上的.forceUpdate.spyOn.导航正确完成后,无论调用哪种内部方法都无关紧要

I believe you don't need either .forceUpdate nor .spyOn on instance method. once navigation happens properly it does not matter by what internal method it has been called

有关微任务与宏任务的更多信息: https://abc.danch.me/microtasks-macrotasks-more-on-the-event-loop-881557d7af6f

more on microtask vs macrotask: https://abc.danch.me/microtasks-macrotasks-more-on-the-event-loop-881557d7af6f

替代方法是使用macrotask(setTimeout(...., 0))

alternative is to use macrotask(setTimeout(...., 0))

it('should close the modal', (done) => {
      const wrapper = renderComponent();
      component
        .find({ testID: 'close-icon' })
        .props()
        .onPress();
      setTimeout(() => {
        expect(navigation.state.params.onGoBack).toHaveBeenCalled(); 
        expect(navigation.navigate).toHaveBeenCalledWith("Main");
        done();
    });
}

这篇关于如何使用spyOn测试异步功能?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆