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();
  })
});
总结

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

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

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

猜你喜欢

转载自blog.csdn.net/weixin_53961451/article/details/143530103
今日推荐