现在是2025年,停止使用快照测试!

6 小时前   出处: medium  作/译者:Alex Hamer/溜的一比

我记得快照测试刚出现时的情景,那时是 Enzyme 的时代。它是最新的酷技术,许多人纷纷开始在他们的 React 应用程序中广泛使用它。

从表面上看,快照测试似乎提供了很多好处,但在我看来,它们只是前端的一时风潮,其使用方式并没有被充分理解。在许多情况下,它们实际上降低了应用程序的测试质量……现在已经是2025年了,我仍然看到一些例子,快照测试仍然是应用程序组件测试覆盖率的一个重要部分。

以下是我认为快照测试对测试质量产生负面影响的原因,以及为什么我认为你应该停止使用它们(如果你仍在使用的话):

1. 快照假设组件在做正确的事情

当快照被创建时,它假设组件在做正确的事情。这是一个很大的假设,而快照本身很难让这一点变得明显。这种假设有多常见?非常常见!我见过许多快照把错误当作正确的输出进行验证。🐛

2. 快照过载

我观察到一些团队在其测试策略中严重依赖快照测试。他们为组件中的每一个路径都创建了快照。快照文件变得非常庞大,没人愿意去看它,甚至 GitHub 可能也会试图隐藏它,因为它不想处理文件的大小!内联快照可能会有所帮助,但我从未看到过很好的应用。现实是,我们有一堆机器生成的代码,期望工程师在软件交付过程中必须翻阅这些代码。😫

3. 快照失败很难理解

当一个快照失败时,很难快速有效地理解失败的原因。是回归问题吗?如果是,具体是哪里出了问题?我们只知道输出发生了变化。如果不明显,并且你不走运,可能得翻遍快照来更好地理解问题,同时祈祷快照尽可能简洁。🙏

4. 快照失败可能不是回归

快照并不符合测试驱动开发(如果你追求的是这一点)。你只有在代码写好后才能创建快照。因此,快照失败的原因有很多,可能并非回归问题。也许你重构了组件的类名,那就是失败。你修改了 HTML 元素以改善可访问性,那也是失败。你的测试现在与 DOM 结构耦合了!这不是理想的状态。⚠️

5. 简单的变化可能导致代码库中的大量失败

React Testing Library 提倡将一个组件和所有其子组件一起进行测试。我见过类似的做法应用于快照测试。实际上,这意味着当一个子组件发生微小变化(例如类名的简单变化)时,我们会看到代码库中大量的测试失败。然后,这需要时间和精力来解决。维护这种方式的价值值得怀疑。🚧

6. 没有工程师愿意花时间阅读快照

即使是最勤奋、最注重质量的工程师,也不会愿意定期花时间翻阅计算机生成的快照。大快照很常见,失败也很频繁,这就像是在稻草堆里找针一样。错误是常见的,当工程师的眼睛因为又要翻阅400行快照而烧灼时,运行 jest --u​ 的冲动就会很强烈。😱

7. 工程师变得对真实的回归问题视而不见

这就像是狼来了的故事。快照测试失败的频率很高,加上审查失败的时间和精力,导致工程师变得条件反射地在快照失败时仅仅更新快照。失败的情况审查得越来越少,bug 就悄悄漏网了,如果其他测试覆盖面假设快照“已覆盖”了这些问题的话。🐛

8. 测试意图不明确

在我看来,组件测试应该是一个很好的文档,供其他工程师快速理解组件的工作方式。大多数我见过的快照测试根本没有提供这种帮助。

在这些测试中,我经常看到一句话:“应该正确渲染”。“正确”到底意味着什么?没有任何先验知识,其他工程师怎么理解什么是“正确”?嗯,我得回到快照中,解读那段机器生成的代码,看看“正确”到底是什么意思……同时祈祷在创建快照时没有做出错误的假设。😱

// 这个测试并没有记录组件实际做了什么
// 我们需要查看快照才能更好地理解
describe("我的复杂组件", () => { 
  it("应该正确渲染", () => { 
    const { container } = render(<MyComponent />); 

    expect(container).toMatchSnapshot(); 
  }); 
});

9. 增加代码覆盖不完整的可能性

当快照被过度依赖且测试意图不明确、文档不清晰时,很可能导致代码覆盖不完整。

一个笼统的“应该正确渲染”测试通常会掩盖组件可能采取的不同分支和条件,通常只会覆盖到“快乐路径”。这会导致一种虚假的安全感。如果代码中有任何分支,它们往往会被遗漏或未完全覆盖,对于审查的工程师来说,这通常不明显。

测试覆盖受到影响,测试质量下降,bug 也就悄悄溜入了。🐛

10. 替代方案是什么?

那么,如果我们要放弃快照测试,替代方案是什么呢?答案其实并不复杂,关键是依赖明确的测试断言,并结合良好的测试标准。不要把组件的细节埋在大量的快照输出中。为下一个开发者编写测试。

良好的标准意味着:

  • 明确组织的测试,清楚地知道:在测试什么,测试的具体场景是什么,预期的结果是什么
  • 清晰的测试语句和断言
  • 集中的测试范围,保持测试的专注性,不要让测试被过多的断言所干扰
  • 测试所有代码路径(在类型检查可以验证的情况下,不必让测试过于冗长)
  • 以用户的方式测试组件

一个简化的例子: 停止这样做……

it('应该正确渲染', () => {
  const { container } = render(<MyComponent {...props} />);

  expect(container).toMatchSnapshot();
});

it('当按钮被点击时,应该正确渲染', () => {
   const { container } = render(<MyComponent {...props} />);

   const button = screen.getByRole('button', { name: /add/i });
   userEvent.click(button);

   expect(container).toMatchSnapshot();
});

改成这样做……

it('应该渲染一个添加按钮', () => {
  render(<MyComponent {...props} />);

  expect(screen.getByRole('button')).toHaveTextContent('Add')
});

it('当按钮被点击时,按钮应该被禁用', () => {
  render(<MyComponent {...props} />);

  const button = screen.getByRole('button', { name: /add/i });
  userEvent.click(button);

  expect(screen.getByRole('button')).toBeDisabled()
});

组件测试应该容易编写,而不需要依赖快照(如果你依赖快照,你应该认真考虑重构)。实际上,在当前的 AI 环境中,像 Copilot 这样的工具意味着你甚至不需要自己编写它们!没有借口了。

其他人可能会提出有效的观点,认为快照可以捕捉到你的 DOM 中一些微妙的回归问题,而这些问题可能会被你的替代测试忽略。但在我看来,它们只是半心半意的测试覆盖,和像视觉回归测试这样从用户角度出发的测试相比,它们提供的信心有限,而且弊大于利。

节省时间和精力,去除快照 组件快照所带来的任何价值,都被它们给团队带来的维护麻烦和低效所大大抵消。

测试质量下降,测试覆盖受到影响,bug 也就悄悄进入。用全面且容易理解的高质量测试替代你的快照,我相信你的团队会变得更加高效、快乐,产出更高质量的成果。


声明:本文为本站编辑转载,文章版权归原作者所有。文章内容为作者个人观点,本站只提供转载参考(依行业惯例严格标明出处和作译者),目的在于传递更多专业信息,普惠测试相关从业者,开源分享,推动行业交流和进步。 如涉及作品内容、版权和其它问题,请原作者及时与本站联系(QQ:1017718740),我们将第一时间进行处理。本站拥有对此声明的最终解释权!欢迎大家通过新浪微博(@测试窝)或微信公众号(测试窝)关注我们,与我们的编辑和其他窝友交流。
/18 人阅读/0 条评论 发表评论

登录 后发表评论
最新文章