介绍
快照测试允许您确保您的输出继续按预期运行。这很有用,因为随着您重新访问代码以随着时间的推移进行更新,这些更改可能会导致某些内容中断的可能性增加。
与严格的测试驱动开发 (TDD) 不同,TDD 的标准做法是先编写失败的测试,然后编写代码以使测试通过,快照测试采用不同的方法。
在为 React 组件编写快照测试时,首先需要让代码处于工作状态。然后,在给定某些数据的情况下生成其预期输出的快照。快照测试与组件一起提交。Jest 是一个测试框架,会将快照与测试的渲染输出进行比较。
如果测试失败,则可能意味着两件事。如果测试结果出乎意料,您可能需要解决组件的问题。如果测试结果符合预期,则可能意味着需要更新快照测试以支持新的输出。
在本教程中,您将探索快照测试以及如何使用它们来确保您的用户界面 (UI) 不会意外更改。
先决条件
要完成本教程,您需要:
- Node.js 安装在本地,您可以按照如何安装 Node.js 和创建本地开发环境来完成。
- 熟悉React和Jest可能会有所帮助,但不是必需的。
本教程还使用Visual Studio Code作为代码编辑器,以方便运行集成终端。但是,您可以将其替换为您选择的编辑器和终端。
本教程已通过 Node v14.7.0、npm
v6.14.7、react
v16.13.1 和jest
v24.9.0 验证。
第 1 步——创建一个 React 组件进行测试
首先,为了进行测试,您需要使用Create React App创建一个React App。在本教程中,该项目将被称为react-snapshot-tests
。
打开终端并运行以下命令:
- npx create-react-app@3.4.1 react-snapshot-tests
然后,切换到新创建的应用程序目录:
- cd react-snapshot-tests
接下来,启动应用程序:
- npm start
此时,您现在应该运行了一个 React 应用程序,并且可以在 Web 浏览器中查看它。接下来,您需要创建一个可以测试的组件。
就本教程而言,您将要创建的组件会渲染items
它接收到的道具。
在您的终端中,在以下components
目录下创建一个子目录src
:
- mkdir src/components
然后,创建一个Items.js
组件:
- nano src/components/Items.js
将以下代码添加到Items.js
:
import React from 'react';
import PropTypes from 'prop-types';
/**
* Render a list of items
*
* @param {Object} props - List of items
*/
function Items(props) {
const { items = [] } = props;
// A single item in the list, render a span.
if (items.length === 1) {
return <span>{items[0]}</span>;
}
// Multiple items on the list, render a list.
if (items.length > 1) {
return (
<ul>
{items.map(item => <li key={item}>{item}</li>)}
</ul>
);
}
// No items on the list, render an empty message.
return <span>No items in list</span>;
}
Items.propTypes = {
items: PropTypes.array,
};
Items.defaultProps = {
items: []
};
export default Items;
此代码将items
根据数量呈现道具:
- 如果有多个项目,项目将显示在一个无序列表 (
<ul>
) 中。 - 如果有单个项目,则该项目将显示在一个
<span>
元素中。 - 如果没有项目,将显示错误消息。
最后,更新App.js
以呈现我们的组件:
- nano src/App.js
将 的内容替换App.js
为以下内容:
import React, { Component } from 'react';
import Items from './components/Items';
class App extends Component {
render() {
const items = [
'Shark',
'Dolphin',
'Octopus'
];
return (
<Items items={items} />
);
}
}
export default App;
如果您在浏览器中访问该应用程序,将会出现一个屏幕,其中列出了您在 中建立的值App.js
:
Output* Shark
* Dolphin
* Octopus
由于有多个items
,它显示为一个无序列表。
接下来,您将添加快照测试。
第 2 步 – 编写快照测试
首先,删除App.test.js
由 Create React App 生成的文件:
- rm src/App.test.js
本教程不需要它。
接下来,安装react-test-renderer
一个库,它使您能够将 React 组件呈现为 JavaScript 对象,而无需 DOM。
- npm install react-test-renderer@16.13.1
让我们添加您的第一个测试。首先,您将创建一个Items.test.js
文件:
- nano src/components/Items.test.js
编写一个测试来渲染Items
没有项目作为 props 传递的组件:
import React from 'react';
import renderer from 'react-test-renderer';
import Items from './Items';
it('renders correctly when there are no items', () => {
const tree = renderer.create(<Items />).toJSON();
expect(tree).toMatchSnapshot();
});
接下来,让我们运行测试。Create React App 处理了设置测试的所有初始化:
- npm test
您应该通过以下测试"renders correctly when there are no items"
:
当您第一次运行快照测试时,请注意在__snapshots__
目录中创建了一个新的快照文件。由于您的测试文件已命名Items.test.js
,因此快照文件的名称也适当Items.test.js.snap
。
的内容Items.tests.js.snap
应该类似于:
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`renders correctly when there are no items 1`] = `
<span>
No items in list
</span>
`;
此快照与组件的确切输出相匹配。
Jest 用于pretty-format
使快照文件可读。
您现在可以为有一个项目和多个项目的另外两个场景创建测试。
打开Items.tests.js
:
- nano src/components/Items.test.js
添加以下代码行:
// ...
it('renders correctly when there is a single item', () => {
const items = ['one'];
const tree = renderer.create(<Items items={items} />).toJSON();
expect(tree).toMatchSnapshot();
});
it('renders correctly when there are multiple items', () => {
const items = ['one', 'two', 'three'];
const tree = renderer.create(<Items items={items} />).toJSON();
expect(tree).toMatchSnapshot();
});
此时,您编写了三个测试:一个针对无项目,一个针对单个项目,另一个针对多个项目。
重新运行测试:
- npm test
所有三个测试都应该成功通过,现在您的__snapshots__
目录中将拥有三个快照。
接下来,您将通过更新快照测试来解决失败的测试。
第 3 步 – 更新快照测试
为了更好地理解为什么需要快照测试,您将对Items
组件进行更改并重新运行测试。这将模拟对开发中的项目进行更改时会发生的情况。
打开Items.js
:
- nano src/components/Items.js
将类名添加到span
和li
元素:
...
/**
* Render a list of items
*
* @param {Object} props - List of items
*/
function Items(props) {
const { items = [] } = props;
// A single item in the list, render a span.
if (items.length === 1) {
return <span className="item-message">{items[0]}</span>;
}
// Multiple items on the list, render a list.
if (items.length > 1) {
return (
<ul>
{items.map(item => <li key={item} className="item-message">{item}</li>)}
</ul>
);
}
// No items on the list, render an empty message.
return <span className="empty-message">No items in list</span>;
}
Items.propTypes = {
items: PropTypes.array,
};
Items.defaultProps = {
items: [],
};
export default Items;
让我们重新运行测试:
- npm test
您将观察到失败的测试结果:
Jest 将现有快照与具有更新更改的呈现组件进行匹配,但失败了,因为您的组件添加了一些内容。然后它显示了引入快照测试的更改的差异。
如果更改不是预期的,您会在部署更改之前发现错误,现在可以解决错误。如果更改是预期的,则需要更新快照测试以使它们正确通过。
对于本教程,您可以假设这是预期的更改。您打算向组件添加类名。然后您应该更新快照测试。
当 Jest 处于交互模式时,您可以通过按u
提供的选项来更新快照测试:
注意:或者,如果您全局安装了Jest,则可以运行jest --updateSnapshot
或jest -u
。
这将更新快照以匹配您所做的更新,并且您的测试将通过。
这是之前没有项目的快照测试:
// ...
exports[`renders correctly when there are no items 1`] = `
<span>
No items in list
</span>
`;
// ...
这是新更新的无项目快照测试:
// ...
exports[`renders correctly when there are no items 1`] = `
<span
className="empty-message"
>
No items in list
</span>
`;
// ...
更新测试后,他们将通过:
您现在再次通过了测试。如果这是一个正在开发的项目,您可以部署代码,知道您打算进行的更改已记录在案以供将来开发。
结论
在本教程中,您为 React 组件编写了快照测试。您还修改了组件以体验失败的测试。最后,您更新了快照以修复测试。
这是对现场项目的小型模拟。这种测试通过、失败和解决失败的循环将成为您开发工作流程的一部分。
快照测试旨在成为许多不同的测试工具之一。因此,您可能仍然需要为您的操作和减速器编写测试。
虽然您已经探索了快照测试的基础知识,但您可以学到很多关于编写更好的快照测试的知识。请查看Jest 文档中的Snapshot 最佳实践,以了解有关快照测试的更多信息。
如果您想了解有关 React 的更多信息,请查看我们的 React 主题页面以获取练习和编程项目。