如果你使用Jest的快照测试来做你的组件,有几个陷阱是你必须要注意的。其中两个也很可能适用于你的书面测试:
-
- 如果实际的快照测试渲染了一个有很多子组件的组件,那么快照测试的输出往往变得太大。这本身就有两个问题。A) 你不能仅仅通过查看快照输出来确定其差异,B) 如果你对你的子组件也进行快照测试,那么你的快照输出会有点重复。
-
- 如果你的实际快照测试组件渲染了很多子组件,所有子组件的道具都需要在父组件的快照测试中设置。因此,你并没有真正关注父组件,而是在为子组件设置所有必要的信息。如果你在分离测试中再次测试你的子组件,这项任务就会变得重复,因为在那里你必须用同样的道具设置来测试它们。最终,你将会得到重复的测试设置。
正如你所看到的,这两个问题只适用于渲染几个以上的子组件的父组件。那么,如果你能在你的快照测试中浅浅地渲染父组件,只关注测试中的父组件;关注它是否渲染了其子组件的实例,而不担心子组件的整个输出呢?
如果你使用Jest进行快照测试,你很可能是用react-test-renderer渲染你的React组件:
import React from 'react';
import renderer from 'react-test-renderer';
import Profile from '.';
describe('Profile', () => {
it('renders', () => {
const component = renderer.create(<Profile />);
const tree = component.toJSON();
expect(tree).toMatchSnapshot();
});
});
如果你在你的Profile组件中渲染大量的子组件,你的快照测试输出可能会出现问题1)。不过你唯一应该关心的是渲染的组件实例,而不是它们的内容。
const Profile = () => (
<>
<Preferences />
<Documents />
<WorkExperience />
<Education />
<Skills />
<PersonalInfo />
</>
);
如果Profile组件向其所有的子组件传递大量的props,你就会出现问题2),因为你必须在快照测试中为所有的子组件设置所有的假props,即使父组件可能不关心它们。
const Profile = ({
...preferencesProps,
...documentsProps,
...workExperienceProps,
...educationProps,
...skillsProps,
...personalInfoProps,
}) => (
<>
<Preferences {...preferencesProps} />
<Documents {...documentsProps} />
<WorkExperience {...workExperienceProps} />
<Education {...educationProps} />
<Skills {...skillsProps} />
<PersonalInfo {...personalInfoProps} />
</>
);
你想在快照测试中避免1)和2),因为这些问题应该在子组件中测试。父组件可能只关心渲染子组件。
注意:浅层渲染快照测试不是你整体测试策略的银弹。如果你在快照测试中应用浅层渲染,你可能会失去对你的组件在集成中工作的信心(例如,父组件和子组件之间的相互作用)。
即使React的测试渲染器提供了浅层渲染,我发现模拟子组件的渲染输出是更适合我的测试案例的方法。
import React from 'react';
import renderer from 'react-test-renderer';
import Profile from '.';
jest.mock('./Preferences', () => () => 'Preferences');
jest.mock('./Documents', () => () => 'Documents');
jest.mock('./WorkExperience', () => () => 'WorkExperience');
jest.mock('./Education', () => () => 'Education');
jest.mock('./Skills', () => () => 'Skills');
jest.mock('./PersonalInfo', () => () => 'PersonalInfo');
describe('Profile', () => {
it('renders', () => {
const component = renderer.create(<Profile />);
const tree = component.toJSON();
expect(tree).toMatchSnapshot();
});
});
你的浅层渲染的快照测试的输出看起来类似于下面:
exports[`Profile renders 1`] = `
Array [ "Preferences", "Documents", "WorkExperience", "Education", "Skills", "PersonalInfo",]
`;
与将所有子组件渲染到最大程度的版本相比,这是一种简化的方式。同时,你也不需要再去关心传递的道具。然而,如果你想测试你的父组件是否将所有必要的道具传递给它的子组件,你甚至可以用一个模拟的子组件来测试它。
import React from 'react';
import renderer from 'react-test-renderer';
import Profile from '.';
import PersonalInfo from './PersonalInfo';
jest.mock('./Preferences', () => () => 'Preferences');
jest.mock('./Documents', () => () => 'Documents');
jest.mock('./WorkExperience', () => () => 'WorkExperience');
jest.mock('./Education', () => () => 'Education');
jest.mock('./Skills', () => () => 'Skills');
jest.mock('./PersonalInfo', () => () => 'PersonalInfo');
describe('Profile', () => {
it('renders and passes props', () => {
const component = renderer.create(<Profile />);
const tree = component.toJSON();
expect(tree).toMatchSnapshot();
expect(component.root.findByType(PersonalInfo).props).toEqual({
name: 'Robin Wieruch',
});
});
});
总之,你最终会得到一个非常轻量级的父组件的快照测试,而你会用他们的道具更彻底地快照测试你的子组件(如偏好、文档、教育、技能)。