前端单元测试之殇
使用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分离,前端能够更加专注于逻辑测试,提高逻辑的稳定性。
文中的例子比较简单,也非常容易测试,后面将会介绍一些更复杂例子的单元测试,书写可测试的代码将会受益匪浅。