不要对 UI 组件进行快照,要做出断言!
问题
解决方案
结论
快照是测试的绝佳工具。它能够确保每次执行的结果始终与之前完全相同,这对于纯函数单元测试来说绝对有用。UI 组件是(或者说应该是)纯函数,那么,为什么本文标题说我们不应该将它用于 UI 组件呢?请允许我解释一下。
问题
让我们想象一下以下情况。你开发了一个卡片组件,用于在你的个人博客上显示一张图片和博客文章的标题。然后你决定为该组件编写单元测试,以确保它能够同时显示图片和标题。
这很简单,只需拍摄快照,就可以了,对吗?
让我们把它写下来:
describe('Card', () => {
it('should show image and title', () => {
const { asFragment } = render(() =>
<Card image={/*some url*/} title="Title of my Post" />)
expect(asFragment()).toMatchSnapshot()
})
})
轰!你的快照现在包含了整个组件的标记。一切搞定!
现在,你想在组件中添加一个按钮,这样你的读者就能直接跳转到帖子阅读了,因为你确实希望人们阅读你的帖子。你做了修改,启动了博客的开发服务器,它就在那里,运行良好。
然后你运行测试但测试失败了......
您阅读了测试描述“应该显示图像和标题”,查看了博客的开发版本,您可以清楚地看到图像和标题都显示了,还有新的闪亮按钮。
我听到你说:“好吧,别傻了,只需更新你的快照!”
更新快照
你说得对,我忘了更新我的快照了。现在我得看看快照,比较一下新旧标记,看看这些更改是否是有意为之,然后更新它。
我有一个问题要问你:是谁做出的断言,是你还是你的测试?
使用一个组件来做到这一点很容易,但是如果您有 50 个不同的组件使用更改后的组件并且所有快照测试都中断,会发生什么情况?
我们编写测试是为了确保组件能够按其需求运行,履行其约定。当你做出断言而不是测试时,你就互换了角色。这实际上与手动测试相同。
而且,这种行为非常危险。它会让你陷入这样一种思维定式:“我修改了标记,只需更新快照,无需检查”。这样你就会轻易地把一个有问题的组件塞进去。
测试弹性
我们还可以谈谈测试的弹性。测试表明它同时显示了图片和标题。虽然快照确实显示了它们都存在,但它实际上的作用远不止于此。快照确保组件的输出与之前完全相同。这使得你的代码库难以重构,这肯定不是一件好事。
你的测试不应该关心实现方式,而应该关心结果以及是否符合规范。这样你就可以确保测试不会出现假阴性。无论最终如何实现,只要图片和标题显示在最终标记上,测试就不应该失败。
解决方案
我希望现在您能够理解我关于为什么快照 UI 是一个坏主意的理由。
解决方案很简单:做出断言!
我同意,几年前这确实很烦人。但现在我们有了@testing-library,它有超级棒的查询功能,比如getByText
、getByRole
等等。如果你没听说过,可以去看看。它真的很棒。
让我们使用它们进行重构:
describe('Card', () => {
it('should show image and title', () => {
const title = "Title of my post"
const url = "some url for the image"
const altText = "description of the image"
const { getByText, getByAltText } = render(() =>
<Card image={url} title={title} />)
getByText(title)
expect(getByAltText(altText)).toHaveAttribute('src', url)
})
})
一些注意事项:
- 有意义的错误消息。快照将找出组件问题的工作交给了您。您是进行比较的人。您确实会得到一个不错的差异,但仅此而已。通过此重构,现在错误消息会真正告诉您哪里出了问题。可能是找不到组件(这意味着您以某种方式搞砸了渲染),或者您更改了组件的 API 并且没有更新测试以覆盖所有更改。
- 没有误报。现在,如果您以任何方式更改标记,添加或删除除图像和标题之外的任何内容,测试都不会失败,您可以安全地迭代此组件并对其进行重构,以使其在将来变得更好。
- 您正在像用户一样使用组件。提供的查询
dom-testing-library
强制您像用户一样使用组件(例如,查找屏幕上的文本或查找图像的替代文本)。
结论
为 UI 组件编写快照测试弊大于利。它会强制代码库拒绝更改。另一方面,测试其行为并进行具体的断言,则不会产生错误警报,反而会产生更有意义的错误消息。
你对此有何感想?请在下方评论区留言,分享你的想法。让我们一起讨论学习。
鏂囩珷鏉ユ簮锛�https://dev.to/frontendwizard/don-t-snapshot-your-ui-components-make-assertions-41b5