【问题标题】:Mock function not being called with react-testing-library, but original function is called未使用 react-testing-library 调用模拟函数,但调用了原始函数
【发布时间】:2021-11-12 02:02:12
【问题描述】:

我想,我有一个简单的案例。我在我的组件中使用了一个从不同文件导入的函数。我已经模拟了如下所示的函数。我也尝试过添加一个模拟实现,但这也不起作用。如果我在我的原始函数中添加了一条打印语句,它会在我运行测试时出现。如果我理解正确,模拟应该替换原来的。

我尽量让这件事简单明了,所以我不确定我错过了什么。

测试文件:

import AddStoryModal from './AddStoryModal';
import addStory from '../api/add_story';

jest.mock('../api/add_story');

describe('Story tests', () => {

  it('makes an API call to add a story', () => {
    render(<AddStoryModal />);

    const submitButton = screen.getByTestId('add-submit');  
    fireEvent.click(submitButton);
    expect(addStory).toHaveBeenCalled();
  });
});

结果:

 expect(jest.fn()).toBeCalled()

    Expected number of calls: >= 1
    Received number of calls:    0

正在测试的组件:

...
import addStory from '../api/add_story';

function AddStoryModal(){

  const onFinish = (values) => {
    addStory();
  };

  return (
    <>
      <Button type="primary" data-testid="add-story" onClick={showModal}>
        Create New +
      </Button>

      <Modal title="Add New Story ..." visible={visible} data-testid='add-story-modal' onCancel={handleCancel} footer={null}>
        <Form form={form} layout="vertical" onFinish={onFinish}>
          ...
          <Form.Item>
            <Button type="primary" data-testid="add-submit" htmlType="submit">
              Submit
            </Button>
          </Form.Item>
        </Form>
      </Modal>
    </>
  );
}

【问题讨论】:

    标签: reactjs jestjs react-testing-library


    【解决方案1】:

    这是一个很好的例子,说明编写测试如何使您的生产代码更好。是的,您可以继续使用jest.mock(*module*) 并找出问题所在,但是为什么

    看看AddStoryModal 实际在做什么。它与调用 API 函数非常耦合,这反过来又使测试变得尴尬。

    如果您onFinish 实现函数作为道具传递,您会立即获得一些巨大的胜利:

    • AddStoryModal 中的代码更少
    • 它变得更加通用(并增加了被重复使用的机会)
    • 测试变得更容易

    AddStoryModal:

    function AddStoryModal(props) {
      return (
       <>
      ...
            <Form form={form} layout="vertical" onFinish={props.onFinish}>
      ...
        </>
      );
    }
    

    现在它对../api/add_story一无所知

    你的测试变成:

    import AddStoryModal from './AddStoryModal';
    
    describe('Story tests', () => {
      it('makes an API call to add a story', () => {
        const finishCallback = jest.fn();
    
        render(<AddStoryModal onFinish={finishCallback} />);
    
        const submitButton = screen.getByTestId('add-submit');
        fireEvent.click(submitButton);
        expect(finishCallback).toHaveBeenCalled();
      });
    });
    

    超级干净的测试,易于理解,更适合 React 方式。

    在您的生产代码中,任何使用 &lt;AddStoryModal /&gt; 的页面现在都只使用 &lt;AddStoryModal onFinish={addStory} /&gt;

    【讨论】:

    • 谢谢@millhouse。是否按照您的建议进行了重构,并创建了一个简化的组件,但即便如此,我还是遇到了同样的失败,即从未调用过模拟函数。
    • 好吧,那么听起来你已经发现了一个错误!仅供参考,我通过在AddStoryModal 中创建一个简单的button 并分配onClick={props.onFinish} 来测试它 - 并且有效。所以我会去看看你的Form 是如何触发它的onFinish 回调的——那里有什么不对的地方,或者当提交按钮被按下时是否有表单验证正在运行,导致onFinish 回调不是开火?
    • 好主意。我会调查的。奇怪的是,如果我将console.log 放入addStory,它确实会运行。在某些世界中,这是onFinish 正在成功。如果/当我整理出来,我会发布。谢谢。
    • 我认为你是对的。我将此视为行为测试,但我想要发生的事件实际上是submit 而不是click。感谢您的帮助!
    猜你喜欢
    • 1970-01-01
    • 2021-11-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-22
    • 2021-07-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多