【问题标题】:Mock a non-default function using Jest and React使用 Jest 和 React 模拟非默认函数
【发布时间】:2019-05-05 06:33:40
【问题描述】:

在一个测试文件中,我需要渲染一个组件,同时模拟它的一些子组件。文件结构大致如下所示。

文件 1

import {A, B} from 'a-module';

export function MyComponent() {
    return (
        <div>
            <A /> // I need to mock
            <B /> // these components out
        </div>
    );
}

文件 2

import {MyComponent} from 'File 1';

/*
 * In this file I would like to render MyComponent but
 * have components A and B be replaced by mocks
 */

我尝试过jest.mock('a-module', () =&gt; 'Blah');,但这并没有成功地模拟组件。但是,当在文件 1 中使用默认导入时,此方法有效。

如果在文件 2 中渲染 MyComponent 时模拟出组件 AB,将不胜感激!

【问题讨论】:

    标签: javascript reactjs unit-testing webpack jestjs


    【解决方案1】:

    您可以像这样模拟非默认值:

    jest.mock('a-module', () => ({
      __esModule: true,
      default: () => 'Blah',
      A: () => 'Blah',
      B: () => 'Blah'
    }));
    

    https://remarkablemark.org/blog/2018/06/28/jest-mock-default-named-export/

    或使用 __mocks__

    作为替代方案,您可以在原始模块旁边的__mocks__ 文件夹下创建一个与模块同名的文件:

    a_module_folder > 
        a-module.js
        __mocks__ >
            a-module.js
    

    并且该模拟应该只导出模拟版本:

    export const A = () => 'Blah';
    export const B = () => 'Blah';
    

    然后像这样模拟:

    jest.mock('a-module');

    对于 node_modules,只需将 __mocks__folder 与 node_modules 放在同一级别

    https://jestjs.io/docs/en/manual-mocks

    【讨论】:

    • 您对我们为什么需要设置 __esModule 有进一步的了解吗?如果没有该选项,它似乎可以工作。
    • 我认为只有当您还需要模拟默认导出时才需要它。见github.com/facebook/jest/blob/…
    【解决方案2】:

    测试 React 组件主要是使用 Enzyme 完成的,如果您只尝试使用 Jest 进行测试,那么您可能选择了错误的工具。我只能猜测您为什么需要模拟一个组件,但您肯定可以使用 Enzyme 来实现它。

    Enzyme 浅层渲染是专门为测试 React 而创建的。 Jest 本身不能渲染组件。根据Airbnb docs的定义是:

    浅渲染有助于限制自己将组件作为一个单元进行测试,并确保您的测试不会间接断言子组件的行为。

    简单地说它将渲染被测组件 1 级深度,例如

    // File2.js
    
    import { MyComponent } from 'File1';
    import { shallow } from 'enzyme';
    
    describe('MyComponent', () => {
      it('should render shallowly my component', () => {
        const wrapper = shallow(<MyComponent />);
        console.log(wrapper.debug()); 
        // output:
        //   <div>
        //     <A />
        //     <B />
        //   </div>
        // Note: even if component <A /> is consisting of some markup, 
        // it won't be rendered 
      });
    });
    

    基本上你不需要模拟它的任何依赖组件,这些已经被酶shallow()模拟了

    您可以做的是在将某些道具传递给&lt;MyComponent /&gt; 时进行测试,依赖组件&lt;A /&gt;&lt;B /&gt; 正在接收预期的道具。

    const wrapper = shallow(<MyComponent foo={1} bar={2} />);
    expect(wrapper.find('A').props().foo).toEqual(1);
    expect(wrapper.find('B').props().bar).toEqual(2);
    

    【讨论】:

    • 我建议不要使用酶进行测试,因为它鼓励将测试与实现细节结合起来。检查反应测试库
    • 你应该测试的是组件的输入和输出。就像你说的,你需要检查一个元素是否是一个按钮(html按钮),但你永远不需要知道里面使用了什么反应组件,有什么内部状态等等。Enzyme 提供并鼓励基于测试的方法反应组件名称(查找)并检查内部状态。这就是我所说的实现细节。测试这些的问题是对实现的更改不会改变输出而破坏测试,更糟糕的是,实际上会破坏输出但仍然通过测试的更改。
    • 谢谢。这是一个很好的答案,如果我应该使用酶,它会让我重新思考,但它并没有直接回答我的问题。
    【解决方案3】:

    如果你有一个不是默认导出的 react 组件,它实际上是一个good practice (since default exports should be avoided)

    export function MyComponentX() {
        return (
            <div>...</div>
        );
    }
    

    你可以轻松地嘲笑它:

    jest.mock('path/to/MyComponentX', () => ({
      MyComponentX: () => <>MOCK_MY_COMPONENT_X</>,
    }));
    

    【讨论】:

      猜你喜欢
      • 2019-04-16
      • 2019-09-12
      • 1970-01-01
      • 2019-09-23
      • 2019-02-25
      • 2019-07-22
      • 2021-08-22
      • 2017-02-23
      • 1970-01-01
      相关资源
      最近更新 更多