当前位置: 首页 > article >正文

Jest进阶知识:测试快照 - 确保组件渲染输出正确

在 React 应用开发中,确保组件的渲染输出正确是一项重要的测试任务。快照测试是一种有效的方法,可以帮助开发者捕捉并验证组件的渲染输出,确保其在不同的情况下保持一致。

什么是快照测试?

快照测试的基本思想是:

  1. 首次运行测试:将组件的渲染输出记录到一个快照文件中。
  2. 后续运行测试:将组件的渲染输出与快照文件进行对比,确保两者一致。

快照测试可以有效地捕获意外的更改,确保组件的渲染输出不会因为代码的改动而发生不必要的变化。

快速上手

假设我们有一个简单的组件 App,它显示一个待办事项列表,并允许用户添加新的事项:

import { useState } from "react";

function App() {
  const [items, setItems] = useState(["苹果", "香蕉", "西瓜"]);
  const [value, setValue] = useState("");
  const lis = items.map((it, idx) => <li key={idx}>{it}</li>);

  function addItem() {
    if (items) {
      const newItems = [...items];
      newItems.push(value);
      setItems(newItems);
      setValue("");
    }
  }
  return (
    <div className="App">
      <input
        type="text"
        value={value}
        onChange={(e) => setValue(e.target.value)}
      />
      <button onClick={addItem}>添加</button>
      <ul>{lis}</ul>
    </div>
  );
}

export default App;

接下来,我们编写测试代码来生成快照:

import { render } from '@testing-library/react';
import App from './App';

test('renders learn react link', () => {
  const { baseElement } = render(<App />);
  expect(baseElement).toMatchSnapshot();
});

首先从 render 方法中解构出 baseElement(注意 render 方法来源于 testing library)

接下来调用了 toMatchSnapshot(这个方法是 jest 提供的方法)来生成快照。

image-20230511092759962

通过执行结果也可以看到,生成了一张快照,并且在我们的项目目录中(和你的测试文件是同级的),生成了一个名为 _snapshots_ 的目录,里面就是一张测试快照,测试快照的本质就是渲染出来的 DOM 的结构的字符串序列。

// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`renders learn react link 1`] = `
<body>
  <div>
    <div
      class="App"
    >
      <input
        type="text"
        value=""
      />
      <button>
        添加
      </button>
      <ul>
        <li>
          苹果
        </li>
        <li>
          香蕉
        </li>
        <li>
          西瓜
        </li>
      </ul>
    </div>
  </div>
</body>
`;

之后在下一次测试的时候,针对这个组件测试,就会将组件渲染出来的 DOM 结构的序列和之前的快照进行一个比对,看是否一致,如果和之前的快照是一致的,那么测试就通过,如果不一致(这一次渲染新增了DOM节点或者少了DOM 节点),那么就说明这一次渲染和之前的渲染不一致的,测试不通过。

如下图所示:

image-20230511093235552
快照测试的注意事项
  1. 快照本身并不验证渲染逻辑是否正确:快照测试的主要目的是防止意外的更改。如果测试失败,需要检查是否有不期望的更改。
  2. 更新快照:如果确定渲染逻辑没有问题,但结构确实需要更改,可以使用 jest --updateSnapshot 命令更新快照。
避免大快照

在复杂的组件中,直接对整个组件进行快照会导致快照文件非常大。为了生成更小的快照,可以只针对特定的部分进行快照:

import { render, screen } from '@testing-library/react';
import App from './App';

test('renders learn react link', () => {
  render(<App />);
  const content = screen.getByTestId('list');
  expect(content).toMatchSnapshot();
});

在这个例子中,我们只针对 TestUI 组件生成快照。

扩展场景
  1. 快照测试不仅适用于组件的 UI 测试,还可以用于其他场景。例如,对于 HTTP 请求的返回结果进行快照测试:
// getUserById.ts
const getUserById = async (id: string) => {
  return request.get('user', {
    params: { id }
  });
};

// getUserById.test.ts
describe('getUserById', () => {
  it('可以获取 userId == 1 的用户', async () => {
    const result = await getUserById('1');
    expect(result).toMatchSnapshot();
  });
});
  1. 很多人喜欢把快照测试等同于组件的 UI 测试,但是快照有些时候在其他的某一些场景下使用也非常方便:
// getUserById.ts
const getUserById = async (id: string) => {
  return request.get('user', {
    params: { id }
  })
}

// getUserById.test.ts
describe('getUserById', () => {
  it('可以获取 userId == 1 的用户', async () => {
    const result = await getUserById('1')
    expect(result).toEqual({
      // 非常巨大的一个 JSON 返回...
    })
  })
});

比如在上面的示例中,http 请求返回的结果是比较大的,这个时候就会有一些冗余的代码,在写 expect 断言的时候就会比较麻烦。

这个时候你就可以使用快照:

// getUserById.ts
const getUserById = async (id: string) => {
  return request.get('user', {
    params: { id }
  })
}

// getUserById.test.ts
describe('getUserById', () => {
  it('可以获取 userId == 1 的用户', async () => {
    const result = await getUserById('1')
    expect(result).toMatchSnapshot();
  })
});
总结

快照测试是一种简单有效的工具,可以帮助开发者确保组件的渲染输出在不同情况下保持一致。通过合理使用快照测试,可以提高代码的可靠性和可维护性。需要注意的是:

  • 生成小快照:只取重要的部分来生成快照,确保快照是可读的。
  • 合理使用快照:快照测试不仅限于组件测试,可以应用于任何可序列化的内容。

通过遵循这些最佳实践,可以避免快照测试中的“假错误”,确保测试的有效性。


http://www.kler.cn/a/380874.html

相关文章:

  • 如何实现圆形头像功能
  • Pytorch | 从零构建MobileNet对CIFAR10进行分类
  • 数学竞赛网站:构建互动学习的网络平台
  • Halcon例程代码解读:安全环检测(附源码|图像下载链接)
  • workman服务端开发模式-应用开发-gateway长链接端工作原理
  • 【快速上手】linux环境下Neo4j的安装与使用
  • 学习记录:js算法(八十六):全排列 II
  • 棋牌游戏防ddos攻击,高防IP好用吗?
  • IO流篇(一、File)
  • 承建网站提高访问者留存率
  • 对于IIC的理解
  • Python小白学习教程从入门到入坑------第二十六课 单例模式(语法进阶)
  • 探索Java与C++中的类成员访问修饰符:从默认设置到封装实践
  • 【系统架构设计师】预测试卷一:论文(包括4篇论文主题对应的写作要点分析)
  • AUTOSAR COM 与 LargeDataCOM 模块解析及 C++ 实现示例
  • Docker:容器编排 Docker Compose
  • WPF中的CommandParameter如何使用
  • 11.04学习
  • 《Python游戏编程入门》注-第4章7
  • 如何封装一个axios,封装axios有哪些好处
  • PHP露营地管理平台小程序系统源码
  • Vue3-hooks代替mixins
  • 20241102在荣品PRO-RK3566开发板使用荣品预编译的buildroot通过iperf2测试AP6256的WIFI网速
  • 【GL09】(算法)卡尔曼滤波
  • HCIA(DHCP服务)
  • C++优选算法七 分治-快排