业务复杂多变迭代快速,加上编写单测其实是耗费一定时间去做的,可能很多人认为编写单元测试是一件吃力不讨好的事儿,不会在项目中主动的去做单元测试,一两年前笔者也是这样的一种心态,对于单测嗤之以鼻,但是随着看的书多了,学习的东西多了,明白了单测可有有效的保证我们一些核心功能的正确性,同样可以反推我们的设计一些通用功能是否全面,再者也可以在我们改动一些功能后,校验原有功能的正确性,说这么多,还需要大家自己写起来单测,一个东西好不好,只有用起来了才知道,在vite下配置jest单测代码一上传至git,有兴趣的朋友,可以点此查阅;
如果我们通过creat-react-app
创建项目会直接内置@testing-library/react
,可以开箱即用,但是这里我们通过vite
方式创建的react项目,vite构建的项目,默认是没有单测的,然后一步步完善test构建,这样做的好处呢就是我们自己熟悉配置构建流程,脱离cli
脚手架工具,自由搭配;
pnpm create vite react-test-example -- --template react-ts
pnpm add @testing-library/react @testing-library/jest-dom jest -D
pnpm jest --init
生成jest配置文件下面我们就对于配置项目做个说明
testMatch: [
'/src/**/__tests__/**/*.{spec,test}.{js,jsx,ts,tsx}' ,
'/src/**/*.{spec,test}.{js,jsx,ts,tsx}' ,
'/__test__/**/*.{spec,test}.{js,jsx,ts,tsx}' ,
],
moduleFileExtensions: [
'ts', 'tsx', 'js', 'jsx'
]
pnpm add identity-obj-proxy -D
处理css文件ts tsx
方式写的单测,我们可以选中用ts-jest
方式快速处理,第二种方式便是通过babel
这种方式配置(繁琐一点),当然说道这儿了,我们得提一嘴今天我这里找到的另一种方式,那就是基于swc
的方案,这套方案优势(我在实际项目亲测)就是执行jest单测文件效率会快过上面两种,速度快的不是一星半点,所以我推荐的用swc
这套方式;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)$',
],
testEnvironment
,现在我们项目上使用最新版本的jest后(jest 28 之后的版本),提示安装的是jest-environment-jsdom
,我们安装后,按照下面配置;testEnvironment: 'jsdom',
setupFiles
相关配置根据具体使用情况增加,后续我们使用@testing-library/react
进行,组件测试都需要依赖@testing-library/js-dom
所以我们就直接设置setupFilesAfterEnv
,将每个单测都需要的公共内容统一添加,具体如下:// ./jest/setupJestDom.ts
import '@testing-library/jest-dom'
// 调整jest.config.js, 增加以下内容
setupFilesAfterEnv: [
'/jest/setupJestDom.ts'
],
setupFiles: [
'@testing-library/react/dont-cleanup-after-each'
],
上面我们做了jest项目的配置,基本上可以满足我们写jest单测了,下面我们就用使用@testing-library/react
方式做一下单元测试的写法,这里我先将@testing-library/react
api文档地址放在这儿,方便参考使用;
首先我们对于常规组件测试写法,具体如下:
import React from 'react'
const HelloWorld: React.FC = () => {
return hello world
}
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( )
// 组件渲染结果打印出来,方便我们去对照
screen.debug()
expect(screen.getByText('hello world')).toBeInTheDocument()
})
})
我们这里总结一下基本用法:
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( )
// 是在写单测不清楚渲染出来的是啥,可以进行debug
screen.debug()
expect(await screen.findByText('hello world')).toBeInTheDocument()
})
})
toBeInTheDocument()
),还记得我们通过setupFiles插入进去的工具库@testing-library/jest-dom
,里面提供了一系列匹配器,方便我们去做test,建议去看官方例子,没必要死记硬背,实际工作要用了就查阅文档;import React, { useState } from 'react'
interface HelloWorldProps {
onClick: () => void
}
const HelloWorld: React.FC = ({ onClick }) => {
return
hello world
}
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( )
// 是在写单测不清楚渲染出来的是啥,可以进行debug
screen.debug()
expect(await screen.findByText('hello world')).toBeInTheDocument()
// 模拟事件
fireEvent.click(screen.getByText(/增加/i))
expect(onClick).toHaveBeenCalledTimes(1)
})
})
针对于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进行单测用法简短说明,喜欢的朋友点赞评论收藏三连一下,谢谢您们的支持~比心!!