使用 Jest 和 React 模拟非默认函数
Posted
技术标签:
【中文标题】使用 Jest 和 React 模拟非默认函数【英文标题】:Mock a non-default function using Jest and 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', () => 'Blah');
,但这并没有成功地模拟组件。但是,当在文件 1 中使用默认导入时,此方法有效。
如果在文件 2 中渲染 MyComponent
时模拟出组件 A
和 B
,将不胜感激!
【问题讨论】:
【参考方案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()
模拟了
您可以做的是在将某些道具传递给<MyComponent />
时进行测试,依赖组件<A />
和<B />
正在接收预期的道具。
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</>,
));
【讨论】:
以上是关于使用 Jest 和 React 模拟非默认函数的主要内容,如果未能解决你的问题,请参考以下文章
Jest / Enzyme - 生命周期方法中的模拟异步函数
Jest + React-testing-library-等待模拟的异步功能完成