react-hooks前端单元测试的曙光

994 阅读3分钟

前端单元测试之殇

使用TDD开发能够带来很多好处。

  • 明确输入输出和代码功能边界
  • 功能模块拆分,可测试
  • 便于代码维护

但是前端单元测试历来都是非常令人头疼的问题,业务更新快,维护UI测试用例让人崩溃到放弃,但是除了UI部分,单纯的逻辑部分可测试的部分很少,因此大部分项目都不写测试用例。

react-hooks期望每个函数功能拆分单一,方便组合复用,同时也方便了单元测试。

小例子--计数器

import * as React from "react";

const { useState } = React;

export default function Counter() {
  const [counter, setCounter] = useState(0);
  const increase = () => setCounter(n => n + 1);
  const decrease = () => setCounter(n => n - 1);

  return (
    <div>
      <button onClick={increase}>Increase</button>
      <span>{counter}</span>
      <button onClick={decrease}>Decrease</button>
    </div>
  );
}

上面例子中的代码逻辑夹杂着UI,一旦UI改变很难测试,如果将逻辑抽离我们就可以非常容易的对逻辑进行测试。书写可测试的代码非常重要,下面我们将代码进行修改,以方便测试

// useCounter.js
import * as React from "react";

const { useState } = React;

export default function useCounter() {
  const [counter, setCounter] = useState(0);
  const increase = () => setCounter(n => n + 1);
  const decrease = () => setCounter(n => n - 1);

  return { counter, increase, decrease }
}

// Counter.js
import * as React from "react";
import useCounter from './useCounter'

export default function Counter() {
  const { counter, increase, decrease } = useCounter();

  return (
    <div>
      <button onClick={increase}>Increase</button>
      <span>{counter}</span>
      <button onClick={decrease}>Decrease</button>
    </div>
  );
}

把计数器分成两部分,一个是计数器逻辑,一个是UI界面。界面部分只需要负责功能组合,而逻辑部分将变得非常容易测试,而这在class时代并不是那么容易。

测试环境搭建

前端测试框架特别多,本文使用jest作为测试工具。

安装

npm i --save-dev jest babel-jest @testing-library/react-hooks
  • jest默认运行test文件夹下的用例,如果需要自定义可以通过jest --init生成的配置文件进行配置
  • babel-jest 是jsx需要babel编译
  • @testing-library/react-hooks 是对react-test-renderer的一个封装

书写测试用例

// useCounter.spec.js
import * as React from 'react'
import { renderHook, act } from '@testing-library/react-hooks'
import useCounter from '../src/components/useCounter'

describe("计数器测试", () => {
  it("初始值", () => {
    const { result } = renderHook(() => useCounter())
    expect(result.current.counter).toBe(0);
  })

  it("加1", () => {
    const { result } = renderHook(() => useCounter())
    act(() => {
      result.current.increase()
    })
    expect(result.current.counter).toBe(1);
  })

  it("减少1", () => {
    const { result } = renderHook(() => useCounter())
    act(() => {
      result.current.decrease()
    })
    expect(result.current.counter).toBe(-1);
  })
})

执行用例

npx jest 或者配置scripts,执行npm run test

总结

react-hooks在一定程度上解决前端单元测试的难题,增大了前端前端测试可测试的范围。逻辑与ui分离,前端能够更加专注于逻辑测试,提高逻辑的稳定性。

文中的例子比较简单,也非常容易测试,后面将会介绍一些更复杂例子的单元测试,书写可测试的代码将会受益匪浅。