250
10
期对这些颜色进行排序。我们可以通过查看“番茄红”是否排在第一位来证明这一
点,因为在
_testColors
中的三种颜色中,它包含最新的时间戳。
让我们再添加一个测试来确保
onRate
onRemove
能够正常工作:
afterEach(() => jest.resetAllMocks())
it("dispatches a REMOVE_COLOR action", () => {
wrapper.find('ColorListMock')
.props()
.onRemove('f9005b4e-975e-433d-a646-79df172e1dbb')
expect(_store.dispatch.mock.calls[0][0])
.toEqual({
id: 'f9005b4e-975e-433d-a646-79df172e1dbb',
type: 'REMOVE_COLOR'
})
})
it("dispatches a RATE_COLOR action", () => {
wrapper.find('ColorListMock')
.props()
.onRate('58d9caee-6ea6-4d7b-9984-65b145031979', 5)
expect(_store.dispatch.mock.calls[0][0])
.toEqual({
id: "58d9caee-6ea6-4d7b-9984-65b145031979",
type: "RATE_COLOR",
rating: 5
})
})
为了测试
onRate
onRemove
,我们不需要模拟实际的单击事件。需要我们做的只是使
用一些信息来触发这些函数的属性,然后验证
Store
dispatch
方法被调用时是否使用
了正确的数据。
调用
onRemove
属性将会导致
Store
分发一个
REMOVE_COLOR
这样的
Action
。调用
onRate
性将会导致
Store
分发
RATE_COLOR
这样一个
Action
。此外,我们还需要确保每次测试完
成后
dispatch
模拟对象被重置了。
能够轻松地将模拟对象注入用户希望测试的模块是
jest
最强大的特性之一。模拟对象
是将测试聚焦于
SUT
的一种非常高效的技术。
快照测试
测试驱动开发是一个测试辅助函数、自定义类和数据集的好方法。然而,在对
UI
进行
测试时,
TDD
可能会变得比较棘手,并且往往是不切实际的。
UI
频繁的变更,使得维
测试
251
UI
测试变成了一种需要耗费大量时间的工作。为已经正式上线的
UI
组件编写测试的
做法也越来越普遍。
快照测试为用户提供了一种可以快速测试
UI
组件的方式,以便确保开发人员没有给组
件带来任何不符合预期的变更。
jest
可以为已渲染的
UI
保存一个快照,以便可以将它
和将来测试中的渲染结果进行比较。这允许用户确保程序更新没有带来任何意想不到
的效果,同时开发人员还可以快速推进项目,并且不会因为
UI
测试的实际工作而陷入
困境。此外,当
UI
变更符合预期时,快照还可以方便地被更新。
我们来看看如何使用快照测试对
Color
组件进行测试的。首先,让我们考察现有的
Color
组件代码:
import { PropTypes, Component } from 'react'
import StarRating from './StarRating'
import TimeAgo from './TimeAgo'
import FaTrash from 'react-icons/lib/fa/trash-o'
import '../../../stylesheets/Color.scss'
class Color extends Component {
render() {
const {
title, color, rating, timestamp, onRemove, onRate
} = this.props
return (
<section className="color" style={this.style}>
<h1 ref="title">{title}</h1>
<button onClick={onRemove}>
<FaTrash />
</button>
<div className="color"
style={{ backgroundColor: color }}>
</div>
<TimeAgo timestamp={timestamp} />
<div>
<StarRating starsSelected={rating} onRate={onRate}/>
</div>
</section>
)
}
}
export default Color
如果我们使用特定属性渲染这个组件,预期获得的
DOM
应该包含基于我们发送的属
性获得的特定组件:
shallow(
252
10
<Color title="Test Color"
color="#F0F0F0"
rating={3}
timestamp="Mon Apr 11 2016 12:54:19 GMT-0700 (PDT)"
/>
).html()
生成的
DOM
应该和下列代码类似:
<section class=\"color\">
<h1>Test Color</h1>
<button><svg /></button>
<div class=\"color\" style=\"background-color:#F0F0F0;\"></div>
<div class=\"time-ago\">4/11/2016</div>
<div>
<div class=\"star-rating\">
<div class=\"star selected\"></div>
<div class=\"star selected\"></div>
<div class=\"star selected\"></div>
<div class=\"star\"></div>
<div class=\"star\"></div>
<p>3 of 5 stars</p>
</div>
</div>
</section>
快照测试允许用户保存我们首次运行某个测试后生成的
DOM
快照。然后我们就可以
把将来的测试和上述快照进行比较,从而确保输出结果总是能够保持一致。
让我们为
Color
组件编写一个快照测试程序:
import { shallow } from 'enzyme'
import Color from '../../../src/components/ui/Color'
describe("<Color /> UI Component", () => {
it("Renders correct properties", () =>
let output = shallow(
<Color title="Test Color"
color="#F0F0F0"
rating={3}
timestamp="Mon Apr 11 2016 12:54:19 GMT-0700 (PDT)"
/>
).html()
expect(output).toMatchSnapshot()
)
})
在这个测试中,我们使用
Enzyme
渲染组件,并将收集到的测试结果作为
HTML
的字符
串处理。
.toMatchSnapshot
jest
用于处理快照测试的匹配器。该测试首次运行时,
测试
253
jset
将会把测试结果的
HTML
另存为一个快照文件。该文件将会保存到与该测试同级
目录下的
__snapshots__
文件夹下。目前,快照文件内容和下列内容类似:
exports[`<Color /> UI Component Renders correct properties 1`] =
`"<section class=\"color\"><h1>Test Color</h1><button><svg ...
后续每次运行该测试时,
jest
将会把测试结果和上述快照进行比较。如果测试结果中
存在和快照不一致的内容,那么该测试将无法成功执行。
快照测试允许用户快速推进项目,但是如果移动得太快,可能会导致开发人员写出一
些稀奇古怪的测试,或者本应该通过的测试也无法正常执行。捕捉
HTML
字符的快照
能够对测试起作用,但是用户很难验证快照是否能够真实地反映实际情况。让我们通
过将输出结果另存为
JSX
的方式来对快照进行改良。
为此,我们将需要安装
enzyme-to-json
模块:
npm install enzyme-to-json --save-dev
该模块提供了一个函数,我们可以通过它将
Enzyme
包装器渲染成
JSX
格式,这使得用
户可以更方便地验证快照输出结果的正确性。
为了使用
enzyme-to-json
渲染快照,我们首先会使用
Enzyme
Color
组件进行浅层渲
染,然后将结果发送给
toJSON
函数,
toJSON
函数的程序执行结果将会传递给
expect
数。我们可能还需要编写一些临时性的代码:
expect(
toJSON(
shallow(
<Color title="Test Color"
color="#F0F0F0"
rating={3}
timestamp="Mon Apr 11 2016 12:54:19 GMT-0700 (PDT)"
/>
)
)
).toMatchSnapshot()
不过这是一个采用合成技术对代码进行改进的绝佳应用场景。还记得合成么?若干
小型函数构造了一个更大的函数。我们可以使用
Redux
compose
函数将
shallow
toJSON
expect
函数构造成一个更大的函数:
import { shallow } from 'enzyme'
import toJSON from 'enzyme-to-json'
import { compose } from 'redux'
import Color from '../../../src/components/ui/Color'
254
10
describe("<Color /> UI Component", () => {
const shallowExpect = compose(expect,toJSON,shallow)
it("Renders correct properties", () =>
shallowExpect(
<Color title="Test Color"
color="#F0F0F0"
rating={3}
timestamp="Mon Apr 11 2016 12:54:19 GMT-0700 (PDT)"
/>
)
.toMatchSnapshot()
)
})
shallowExpect
函数接收一个组件,对它进行浅层渲染并将结果转化为
JSON
格式,然
后将它发送给
expect
函数,最后返回结果给所有
Jest
匹配器。
如果我们运行该测试,它将无法正确执行,因为输出结果是
JSX
格式而非
HTML
字符
串。我们的测试不再需要匹配快照。不过,快照的更新也很容易。我们可以通过再次
执行该测试时声明
updateSnapshot
选项来对快照进行更新。
jest --updateSnapshot
如果我们在执行
Jest
命令时附加了
watch
选项:
jest --watch
jest
将会继续在终端运行,并监听用户对源码和测试程序的变更。如果用户生成了任
何新的变更,
jest
将会再次运行测试。当然用户监控测试时,可以很容易地通过按下
u
键来更新快照:
Snapshot Summary
1 snapshot test failed in 1 test suite. Inspect your code changes or press
`u` to update them.
Test Suites: 1 failed, 6 passed, 7 total
Tests: 1 failed, 28 passed, 29 total
Snapshots: 1 failed, 1 total Time: 1.407s
Ran all test suites.
Watch Usage
Press u to update failing snapshots.
Press p to filter by a filename regex pattern.
Press q to quit watch mode.
Press Enter to trigger a test run.

Get React学习手册 now with O’Reilly online learning.

O’Reilly members experience live online training, plus books, videos, and digital content from 200+ publishers.