Snapshot Test is God
记录一下 snapshot test 的使用心得
我的职业生涯初期几乎没有写过单元测试 。刚开始做 java,在一个国内银行的外包项目组,经理天天都在催进度,测试是不可能测试的。后来做前端,虽然摸索着写了点 nodejs 的测试,研究了 TDD 。但是前端页面是不让测试的,按照我们leader的说法,页面测什么测,不如直接上了,让用户帮我们测。 大概两三年前,进了现在的组,所有的 PR 都要 build pass,而 unit test 是 build pipeline 的重要一环,于是不得不学着写测试。只是这么一写就没法停下来了 -- 是公司没法停下来了,我肯定是不想写的,多一行代码都不想写(😂)。本来就写业务代码而已,现在好了,写了代码还要写测试,改了代码还要改测试。烦死了 。 然后就了解到了 snapshot 测试。
snapshot 测试是个啥
单元测试的核心思想是判定预期输出和实际输出是否相等。举个简单的例子:函数 sum(a, b) 的预期输出是 a + b,那么我们就写一个测试用例,输入 1 和 2,预期输出是 3,然后运行测试,如果实际输出也是 3,那么测试通过,否则测试失败。 snapshot 是一种特殊的测试方法,它会把函数的输出保存下来,作为一个 snapshot 文件。当我们第一次运行测试时,snapshot 文件会被创建,并且保存了函数的输出。以后每次运行测试时,snapshot 文件会被读取,并且和函数的实际输出进行比较。如果两者不相等,那么测试失败,否则测试通过。
为啥说它是个神
一般测试,输出(output)是需要自己管理的。比如 expect(sum(1, 2)).toBe(3),预期输出是 3,我们需要自己写代码来管理这个 output。
而 snapshot 测试,输出是由 snapshot 文件管理的,咱不需要自己哭哈哈的去改测试文件(当然snapshot有变更的情况下还是要人工看一眼的)。如果确定代码没问题,就用 update 指令更新 snapshot 文件就好了。这样就大大降低了测试的维护成本。
再一个,snapshot 测试用来测试组件外观的时候,比 tobeInTheDocument 这种断言效率更高。只需要一行代码 expect(container).toMatchSnapshot() 就可以了,不需要写一大堆断言来判断组件的各个部分是否存在,是否有正确的文本内容,是否有正确的样式等等。只要 snapshot 文件里保存了组件的外观,那么每次运行测试时就可以直接比较组件的外观和 snapshot 文件里的外观,如果两者不相等,那么测试失败,否则测试通过。
另外,虽然 snapshot 的使用依赖 react render,但 并不意味着 snapshot 只能用在 react 上。其实 snapshot 的核心思想是把输出保存下来,作为一个 snapshot 文件,这个思想是可以应用在任何语言和框架上的。只要我们能把函数的输出保存下来,就可以使用 snapshot 测试。比如很复杂的函数,输出是一个对象,我们可以把这个对象保存下来,作为一个 snapshot 文件。以后每次运行测试时,我们就可以把这个对象和 snapshot 文件进行比较,如果两者不相等,那么测试失败,否则测试通过。
在我个人负责的很多模块里,已经大量使用 snapshot 测试,不仅测试了组件的外观,还测试了函数的输出。感觉 snapshot 测试真的很神,降低了测试的维护成本,提高了测试的效率,让我这个不想写测试的人也能轻松地写测试了。
(完)