为什么我不能在jest.Mock中模拟一个函数(必须在spyOn上使用.mockImplementation)?

时间:2019-03-04 16:42:13

标签: unit-testing jestjs enzyme

我希望当我使用jest.mock()模拟一个模块并将函数实现传递给每个对象时,它们将继续进行测试。

import * as services from '_services';

// I thought this would be enough to mock 'load_basket'
jest.mock('_services', () => ({
  load_basket: jest.fn(() => Promise.resolve([]))
}));

describe('WB Component', () => {
  it('loads basket if basket prop is null', () => {

    // However, if I don't use .mockImplemenation here it gives
    // me an error that load_basket wasn't called
    const spy = spyOn(services, 'load_basket').mockImplementation(() => Promise.resolve([]));
    const wrapper = shallow(<WB basket={null} />);
    expect(spy).toHaveBeenCalled();
    wrapper.unmount();
    spy.mockRestore();
  });
});

但是我可以删除.mock中的函数实现并只有load_basket: jest.fn(),但是我不能删除底部的.mockImplementation(() => Promise.resolve([])),否则我将得到expected spy to have been called, but it was not called

编辑:如果我在原始.mock调用或.mockImplementation中都没有函数实现,它将给我一个TypeError: Cannot read property 'then' of undefined ... load_basket是'undefined'。这种方式对我来说很有意义,但是我仍然不明白为什么在.mock中模拟该函数会使其与测试中发现的那个函数不同?

Edit2:load_basket的使用方式如下

class WB extends Component {
  constructor(props) {
    super(props);
    this.state = {
      basket: props.basket,
      loading_basket: !props.basket,
    };
  }

  componentDidMount(): void {
    if (!this.state.basket) {
      load_basket()
        .then(res => {
          this.setState({
            basket: res,
            loading_basket: false
          });
        })
        .catch( ... );
    }
  }

  render () { ... }
}

1 个答案:

答案 0 :(得分:0)

jest.mock接受一个可选的factory参数,如果提供了该参数,则将module替换为调用factory参数的结果。

因此,在调用测试函数时,services.load_basket已经 一个mock function


错误详细信息

您正在呼叫spyOn,但最终呼叫了undocumented legacy Jasmine spyOn functionJest基于Jasmine),我猜您是想呼叫jest.spyOn

spyOn中的Jasmine函数不能与Jest模拟函数一起正常工作,最终会导致您看到的错误,如果您还不模拟实现。

请注意,如果您调用了jest.spyOn,那么它将只是return the existing mock function,因为load_basket已经是一个模拟函数,并且在没有模拟实现的情况下也可以工作。


话虽如此,您无需监视services.load_basket,因为它已经是一个模拟函数

您的测试可以简化为:

import * as services from '_services';

jest.mock('_services', () => ({
  load_basket: jest.fn(() => Promise.resolve([]))
}));

describe('WB Component', () => {
  it('loads basket if basket prop is null', () => {
    const wrapper = shallow(<WB basket={null} />);
    expect(services.load_basket).toHaveBeenCalled();  // Success!
  });
});