业务复杂多变迭代疾速,加上编写单测其实是消耗肯定工夫去做的,可能很多人认为编写单元测试是一件吃力不讨好的事儿,不会在我的项目中被动的去做单元测试,一两年前笔者也是这样的一种心态,对于单测不屑一顾,然而随着看的书多了,学习的货色多了,明确了单测可有无效的保障咱们一些外围性能的正确性,同样能够反推咱们的设计一些通用性能是否全面,再者也能够在咱们改变一些性能后,校验原有性能的正确性,说这么多,还须要大家本人写起来单测,一个货色好不好,只有用起来了才晓得,在 vite 下配置 jest 单测代码一上传至 git,有趣味的敌人,能够点此查阅;
(1)、测试项目筹备
如果咱们通过 creat-react-app
创立我的项目会间接内置 @testing-library/react
,能够开箱即用,然而这里咱们通过vite
形式创立的 react 我的项目,vite 构建的我的项目,默认是没有单测的,而后一步步欠缺 test 构建,这样做的益处呢就是咱们本人相熟配置构建流程,脱离 cli
脚手架工具,自在搭配;
- 1、应用 vite 创立一个空白我的项目
pnpm create vite react-test-example -- --template react-ts
- 2、装置 react 单测相干依赖
pnpm add @testing-library/react @testing-library/jest-dom jest -D
- 3、
pnpm jest --init
生成 jest 配置文件
上面咱们就对于配置我的项目做个阐明
-
第一:咱们先设置匹配那些文件作为 test 文件
testMatch: ['<rootDir>/src/**/__tests__/**/*.{spec,test}.{js,jsx,ts,tsx}', '<rootDir>/src/**/*.{spec,test}.{js,jsx,ts,tsx}', '<rootDir>/__test__/**/*.{spec,test}.{js,jsx,ts,tsx}', ],
-
第二步:配置我的项目单测文件类型配置,留神这个配置内容是从左到右执行去查看匹配的,所以如果是 ts 主导的我的项目,咱们就将 ts 类型文件放在最后面;
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx']
-
第三步:配置文件文件、门路解析方法,执行这个步骤之前,咱们须要对于文件解析工具进行装置,具体如下:
- 1、装置
pnpm add identity-obj-proxy -D
解决 css 文件 - 2、对于 jest 单测文件,因为 jest 是运行在 v8 引擎中,也就是会以 nodejs 环境中来去执行,所以对于文件都要本义操作,惯例有两种形式,第一种
ts tsx
形式写的单测,咱们能够选中用ts-jest
形式疾速解决,第二种形式便是通过babel
这种形式配置(繁琐一点),当然说道这儿了,咱们得提一嘴明天我这里找到的另一种形式,那就是基于swc
的计划,这套计划劣势(我在理论我的项目亲测)就是执行 jest 单测文件效率会快过下面两种,速度快的不是一星半点,所以我举荐的用swc
这套形式; - 3、基于第二步,咱们装置
swc
单测相干工具内容pnpm add @swc/core @swc/jest -D
moduleNameMapper: {'^.+\\.module\\.(css|sass|scss|less)$': 'identity-obj-proxy', '\\.svg$': 'identity-obj-proxy', // webpack or vite 等编译工具中波及到的别名辨认 }, transform: {'^.+\\.(js|jsx|ts|tsx)$': ["@swc/jest"], }, transformIgnorePatterns: ['[/\\\\]node_modules/(?!(antd)/)[/\\\\].+\\.(js|jsx|ts|tsx)$', ],
- 1、装置
-
第四步:以上步骤针对于一般测试文件,如果咱们须要对组件相干测试,咱们就须要配置
testEnvironment
,当初咱们我的项目上应用最新版本的 jest 后(jest 28 之后的版本),提醒装置的是jest-environment-jsdom
,咱们装置后,依照上面配置;testEnvironment: 'jsdom',
-
第五步:下面步骤咱们实现根本版本的 jest 配置,具体对于 coverage 等等这些配置能够查看官网,还有
setupFiles
相干配置依据具体应用状况减少,后续咱们应用@testing-library/react
进行,组件测试都须要依赖@testing-library/js-dom
所以咱们就间接设置setupFilesAfterEnv
,将每个单测都须要的公共内容对立增加,具体如下:// ./jest/setupJestDom.ts import '@testing-library/jest-dom' // 调整 jest.config.js, 减少以下内容 setupFilesAfterEnv: ['<rootDir>/jest/setupJestDom.ts'],
-
第六步:每次执行结束后,不主动清理单测缓存,这样执行效率会快
setupFiles: ['@testing-library/react/dont-cleanup-after-each'],
(2)、@testing-library/react 的根本用法
下面咱们做了 jest 我的项目的配置,基本上能够满足咱们写 jest 单测了,上面咱们就用应用 @testing-library/react
形式做一下单元测试的写法,这里我先将@testing-library/react
api 文档地址放在这儿,不便参考应用;
首先咱们对于惯例组件测试写法,具体如下:
import React from 'react'
const HelloWorld: React.FC = () => {return <div>hello world</div>}
export default HelloWorld
单元测试写法
import React from 'react'
import {render, screen} from '@testing-library/react'
import HelloWorld from '../src/component/HelloWorld'
describe('HelloWorld Component', () => {it('render', () => {render(<HelloWorld></HelloWorld>)
// 组件渲染后果打印进去,不便咱们去对照
screen.debug()
expect(screen.getByText('hello world')).toBeInTheDocument()})
})
咱们这里总结一下根本用法:
- render:渲染 react 组件
- screen:testing-library/react 提供的全局 dom 对象,咱们能够通过 screen 去查 dom 构造
-
查找元素:
findBy...、getBy...、queryBy
,- 对于
getBy... 与 queryBy...
两个用法相似,都是去查找页面内容,返回的是 fiberNode; - 对于
findBy...
返回的是一个 promise,如果页面初始状态没有的元素构造,最终会渲染进去的构造,能够通过这种形式来解决,例如咱们异步申请数据,渲染页面构造,咱们就能够通过 findBy 办法实现,如下所示:
import React from 'react' import {render, screen} from '@testing-library/react' import HelloWorld from '../src/component/HelloWorld' describe('HelloWorld Component', () => {it('render', async () => {render(<HelloWorld></HelloWorld>) // 是在写单测不分明渲染进去的是啥,能够进行 debug screen.debug() expect(await screen.findByText('hello world')).toBeInTheDocument()}) })
- 对于
- 针对 jest-dom 扩大的匹配器(下面用到的
toBeInTheDocument()
),还记得咱们通过 setupFiles 插入进去的工具库@testing-library/jest-dom
,外面提供了一系列匹配器,不便咱们去做 test,倡议去看官网例子,没必要死记硬背,理论工作要用了就查阅文档; -
fireEvent,进行事件模仿单元测试,具体用法如下:
import React, {useState} from 'react' interface HelloWorldProps {onClick: () => void } const HelloWorld: React.FC<HelloWorldProps> = ({onClick}) => { return <div> <div>hello world</div> <button onClick={onClick}> 减少 </button> </div> } export default HelloWorld
单测文件写法如下:
import React from 'react' import {render, screen, fireEvent} from '@testing-library/react' import HelloWorld from '../src/component/HelloWorld' describe('HelloWorld Component', () => {it('render', async () => {const onClick = jest.fn() render(<HelloWorld onClick={onClick}></HelloWorld>) // 是在写单测不分明渲染进去的是啥,能够进行 debug screen.debug() expect(await screen.findByText('hello world')).toBeInTheDocument() // 模仿事件 fireEvent.click(screen.getByText(/ 减少 /i)) expect(onClick).toHaveBeenCalledTimes(1) }) })
(3)、@testing-library/react-hooks 对于 hooks 单元测试方法
针对于 hooks 的单元测试,咱们能够装置
@testing-library/react-hooks
工具进行 hooks 单测,具体装置如下: - 首先,咱们须要装置
pnpm add @testing-library/react-hooks -D
- 其次,咱们须要留神
@testing-library/react-hooks
不与 react 版本捆绑在一起,所以如果咱们须要装置react-test-renderer
或者react-dom
两个其中一个,二者都有,会默认以 react-test-renderer 为第一优先级;
上面对于 hooks 单测如下:
import {useCallback, useState} from "react"
function useCounter() {const [count, setCount] = useState(0)
const increment = useCallback(() => setCount((x) => x + 1), [])
return {count, increment}
}
export default useCounter
import {renderHook, act} from '@testing-library/react-hooks'
import useCounter from '../src/useCounter'
test('Counter', () => {const { result} = renderHook(() => useCounter())
act(() => {result.current.increment()
})
expect(result.current.count).toBe(1)
})
单元测试内容分很多,我这里次要就是我的项目构建,应用 testing-library 进行单测用法简短阐明,喜爱的敌人点赞评论珍藏三连一下,谢谢您们的反对~ 比心!!