快照测试,指的是在测试中首次调用断言方法时,将对象以可读的序列化形式保存起来,然后人工查看一下结果是否正确,如果不正确则重新生成。再次运行测试断言时将对象与保存的快照文件做对比,以确保结果一致,符合预期。
快照测试最大的优点是能轻松地断言复杂的内容,它经常被用于前端项目,因为前端的渲染结果如 HTML、CSS 等都挺复杂,用正则或是其它的工具去匹配它们很费劲,不如直接检查整个结果。
快照测试的缺点是只能比较相等,无法执行大于小于之类的逻辑判断;还有要求对象必须能序列化。
最近撸了一个快照测试工具,感觉挺有用的,便写此文记录和分享一下编写思路。
需求场景
在重构本博客的后端服务时,发现单测里一些结果比较复杂,一条条字段挨个 assert 很是烦人,于是便想到能不能把前端的快照测试搬过来。一番查找只找到两个库 java-snapshot-matcher 和 java-snapshot-testing ,考察后发现它们不太符合我的需求:
java-snapshot-matcher 的快照文件名有问题,仅使用类和方法名,不支持一个方法内多次断言;另外它从调用栈查找测试方法,这在某些情况下是不准确的。
java-snapshot-testing 我不知道他是怎么写出这么多代码的,太复杂了;而且它似乎使用了内置的序列化器,我的项目里自定义了一些类型的序列化方式,必须要求序列化器能够扩展。
嘛总之第三方库都有些问题,还得自己造轮子。我简单地找了一下相关的文章,发现 JAVA 方面快照测试的文章寥寥无几,中文的更是一个没有,我感觉挺好用的一个东西似乎在 JAVA 的世界里不太流行啊。
不过没有教程也无所谓,快照测试的逻辑也不复杂,事实上实现起来相当简单,依靠与现有的系统(AssertJ、IDE)集成,核心功能只要 100 来行代码就搞定了(不算注释)。
基本思路
流程图
基本的流程就是这么简单,首先看看第一步序列化对象,因为要把快照保存为文件,序列化是必不可少的,而且序列化后的格式必须是人类可读的。这里还是选择最常用的 JSON 格式,不得不说 JSON 很是牛B,覆盖了大部分数据类型的同时还有着不错的可读性。博客项目后端使用 Spring 全家桶,自带 JSON 序列化工具 Jackson,用它即可。
第二步更新快照的判断,如果快照文件不存在肯定是要新建,另外像 Jest 一样也支持设置参数 updateSnaoshot 来强制更新,就这两种情况。
最后一个操作是比较,这个直接判断序列化后的字符串是否相等即可。现代的 IDE 比如