業務複雜多變迭代快速,加上編寫單測其實是耗費一定時間去做的,可能很多人認為編寫單元測試是一件吃力不討好的事兒,不會在項目中主動的去做單元測試,一兩年前筆者也是這樣的一種心態,對於單測嗤之以鼻,但是隨着看的書多了,學習的東西多了,明白了單測可有有效的保證我們一些核心功能的正確性,同樣可以反推我們的設計一些通用功能是否全面,再者也可以在我們改動一些功能後,校驗原有功能的正確性,説這麼多,還需要大家自己寫起來單測,一個東西好不好,只有用起來了才知道,在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/reactapi文檔地址放在這兒,方便參考使用;
首先我們對於常規組件測試寫法,具體如下:
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進行單測用法簡短説明,喜歡的朋友點贊評論收藏三連一下,謝謝您們的支持~比心!!