jest手動(dòng)模擬&configuring&cli

本節(jié)內(nèi)容大綱:

  • 手動(dòng)模擬
    • 手動(dòng)模擬自定義模塊
    • 測試第三方模塊lodash
    • 手動(dòng)模擬axios
  • configuring
    • option
  • cli
    • 從命令行運(yùn)行
    • 運(yùn)行
    • jest命令支持駝峰和破折號
    • reference

手動(dòng)模擬

手動(dòng)模擬用于用模擬數(shù)據(jù)存根功能。例如,您可能不想訪問網(wǎng)站或數(shù)據(jù)庫等遠(yuǎn)程資源,而是創(chuàng)建一個(gè)允許您使用虛假數(shù)據(jù)的手動(dòng)模擬。這可確保您的測試快速而穩(wěn)定。

這里分享三個(gè)手動(dòng)模擬:

  • 手動(dòng)模擬自定義模塊
  • 測試第三方模塊lodash
  • 手動(dòng)模擬axios

附帶規(guī)則(謹(jǐn)記):
__mocks__/手動(dòng)模擬是通過在緊鄰模塊的子目錄中編寫模塊來定義的。例如,要模擬目錄user中調(diào)用的模塊models,創(chuàng)建一個(gè)名為的文件user.js并將其放入models/mocks目錄中。請注意,mocks文件夾區(qū)分大小寫,因此MOCKS在某些系統(tǒng)上命名目錄會中斷。

手動(dòng)模擬,此時(shí)的測試文件目錄

手動(dòng)模擬自定義模塊

新建文件__tests__/models/user.ts

// eslint-disable-next-line prefer-const
const utils = {
    count: 12,
    getCount: (num: number) => {
        return num * 20
    }
}
export default utils;

新建文件__tests__/models/mocks/user.ts

const utils = jest.createMockFromModule<typeof import('../user')>('../user');
utils.default.getCount = jest.fn(x => x*10)
utils.default.count = 30;
export default utils.default;

新建測試__tests__/manual/user.test.tsx

import utils from "./models/user";
// import { default as utils } from './models/user'; // 也可以這樣導(dǎo)出
jest.mock('./models/user')
describe('test manual mock',() => {
    test('if original user model', () => {
        // 此時(shí)拿到的數(shù)據(jù)是__mocks__/user.ts重新賦值的內(nèi)容
        // 如果__mocks__/user.ts 中導(dǎo)出不是utils.default,而是utils,那么這里的utils雖然有值,但是測試這個(gè)文件拿到的utils.default為undefined
        console.log(utils,'---') 
        expect(utils.getCount(10)).toBe(100);
    });
})

注意點(diǎn):

  • 由于eslint對于沒有改變的數(shù)據(jù)強(qiáng)行使用const,因此需要忽略這條檢查:eslint-disable-next-line
  • __mocks__中導(dǎo)入的對象,實(shí)際上數(shù)據(jù)保存在一個(gè)default的屬性上,并且導(dǎo)出也必須是導(dǎo)出這個(gè)defualt。因?yàn)樵跍y試文件中無法通過utils.default進(jìn)行訪問
  • createMockFromModule注意他的ts寫法和js寫法的不同,參考文檔:https://www.jestjs.cn/docs/jest-object#jestcreatemockfrommodulemodulename

測試第三方模塊lodash

測試第三方模塊比測試自定義模塊更簡單,我們首先要建立一個(gè)__mocks__文件夾,然后在這個(gè)文件夾里面對第三方模塊進(jìn)行重寫;然后新建測試導(dǎo)入lodash,并且不需要使用jes.mock('lodash')

這里前面已經(jīng)建立了__mocks__,這里只需要在新建文件
__tests__/models/mocks/lodash.ts

// eslint-disable-next-line @typescript-eslint/no-explicit-any
const lodash = jest.createMockFromModule<any>('lodash');

lodash.head = () => 5;
export default lodash;

新建測試__tests__/manual/testLodash.test.tsx

import lodash from 'lodash';
describe('test manual',() => {
    test('if lodash head is mocked', () => {
        expect(lodash.head([2, 3])).toBe(5);
    });
})

注意事項(xiàng):

  • mocks文件默認(rèn)建立在node_module相鄰的目錄中,但是我們項(xiàng)目中的jest.config.js配置了root:"/src/",因此mocks只能放在src及以下的子文件夾內(nèi)
  • 注意ts的寫法,即需要給lodash返回一個(gè)類型,我這里直接寫了一個(gè)any

手動(dòng)模擬axios

測試不會發(fā)起網(wǎng)絡(luò)請求,如果我們執(zhí)意執(zhí)行的話,會提示我們報(bào)錯(cuò)

console.errorError: Error: connect ECONNREFUSED ::1:80at Object.dispatchError (D:\workFile\react-demo\20230505\jest-learn\node_modules\jsdom\lib\jsdom\living\xhr\xhr-utils.js:63:19)

因此我們有兩種方法:一個(gè)是前面聊到的章節(jié)=>模擬異步/模擬axios,如果忘記了可以返回去查看,另一個(gè)方法便是自定義模擬。經(jīng)過前面對自定義模擬的了解,我們知道,如果在一個(gè)ts文件旁邊放一個(gè)__mocks__,并在這個(gè)文件夾里面新建一個(gè)和__mocks__相鄰的同文件名,那么這個(gè)文件將會處于自定義狀態(tài),我們在測試的時(shí)候就只需要jest.mock()指定這個(gè)__mocks__相鄰文件的路徑,就能達(dá)到無需發(fā)起網(wǎng)絡(luò)請求,而自定義返回?cái)?shù)據(jù)的效果。

因此我們新建文件api/__mocks__/home.ts,這樣他就是模擬了api/home.ts文件:

// eslint-disable-next-line @typescript-eslint/no-explicit-any
const home_api: any = jest.createMockFromModule<typeof import('../home')>('../home')

home_api.default.getHomeHead = () => {
    console.log('---')
    return new Promise((resolve) => {
        resolve({
            time: 1,
            title: "news over world"
        })
    })
}
export default home_api.default;

新建測試__tests__/manual/testAxios.test.tsx

import utils from '../../api/home';
// 一定要有,如果沒有的話,那么就變成了單純的方法引入了
jest.mock('../../api/home');

describe('test manual',() => {
    it('test manual axios',async () => {
        console.log(utils,'====')
        const res = await utils.getHomeHead();
        console.log(res,'jjjj')
    })
})

如果這樣跑,大家會出現(xiàn)一個(gè)怪異的問題,那就是導(dǎo)入utils竟然包含一個(gè)default,這是因?yàn)槲覀兾覀兾募pi/__mocks__/home.ts是默認(rèn)導(dǎo)出的,因此得改成導(dǎo)出home_api.default,而不是home_api;改完之后還是不行,因?yàn)閔ome.ts和__mocks__/home.ts在行為上必須一致,即前者默認(rèn)導(dǎo)出,那么后者也需要默認(rèn)導(dǎo)出一次,而我們之前home.ts是單獨(dú)導(dǎo)出的,因此需要改一下:

修改api/home.ts

...
export const getHomeData = async () => {...}

export const getHomeHead = async () => {...}

export const request = (url: string) => {...}

export default {
    request,
    getHomeHead,
    getHomeData
}

這樣,我們才能完美的通過測試。

configuring

Jest 的理念是默認(rèn)情況下工作得很好,但有時(shí)您只需要更多的配置能力。他保存在一個(gè).config.js|ts|mjs|cjs|json文件當(dāng)中,可以直接導(dǎo)出一個(gè)對象或者一個(gè)函數(shù)。這里我主要講解一些平時(shí)我們可能會用到的,后續(xù)講解react組件測試的時(shí)候我會再加上配置運(yùn)行的方法,同時(shí)以下每個(gè)屬性的介紹建議過一遍。

export default {
    verbose: true,  
}
// or
import type {Config} from 'jest';
export default async (): Promise<Config> => {  
    return {    
        verbose: true,  
    };
};

options

jest有很多配置,但是我們并不是需要全部關(guān)心,因?yàn)楣ぷ鳟?dāng)中很少會運(yùn)用到,我們只需要知道一些常用的就行。這里我以我單測遇到的一些配置進(jìn)行講解,當(dāng)看完我這部分的配置之后,相信大家會對單測配置有一個(gè)基本了解,從而讓我們?nèi)タ垂ぷ髦械膉est配置,能夠從容不迫。退一步講,如果還有不明確的,可以查詢官網(wǎng):
https://jestjs.io/docs/configuration#reference

直接上配置(需要注意以下配置,最好是記憶,其余的基本上用不到):

export default {
    // 用作配置jest的基礎(chǔ)字段,這里我們?nèi)绻莟s的項(xiàng)目,可以使用ts-jest,但是前提得先安裝他
    preset: 'ts-jest',
    // 可以參考“從命令行運(yùn)行”內(nèi)容,用于搜索文件目錄路徑的跟頁路徑,一般設(shè)置成如下,這樣我們
    roots: ['<rootDir>/src/'],
    // verbose用于是否開啟報(bào)告每個(gè)單測結(jié)果,默認(rèn)是開啟一個(gè)線池,可以參考“參考reference”的對比圖片
    verbose: false,
    // jest 默認(rèn)測試環(huán)境是node,如果是創(chuàng)建的web應(yīng)用,那么就使用jsdom
    testEnvironment: 'jsdom',
    // 輸出覆蓋范圍的文件目錄,即生成覆蓋率的文件夾名稱
    coverageDirectory: 'coverage',
    // 每次測試前自動(dòng)清除模擬調(diào)用、實(shí)例和結(jié)果
    clearMocks: true,
    // 指示應(yīng)使用哪個(gè)提供程序來檢測覆蓋范圍的代碼
    coverageProvider: "v8",
    // 從正則表達(dá)式到模塊名稱或到允許存根資源的模塊名稱數(shù)組的映射
    // 我們換一種方式去理解:就是供我們配置測試路徑的映射和解析資源的映射,資源包括css和img等,其中圖片和css等資源我們可以,此外
    // 一些第三方的使用如果test無法通過,也可以在這里配置去忽略他
    // 安裝identity-obj-proxy,以下為寫法參考,或者你可以參考“測試React組件”這一節(jié)內(nèi)容
    // 這里面的$1表示正則里面匹配組的序號
    moduleNameMapper: {
        // 處理css等資源
        '\\.(css|scss|less)': 'identity-obj-proxy',
        // 處理圖片等資源
        '\\.(jpg|png|webp|gig|svg|mp4|webm|mp3|m4a|aac)$': 'identity-obj-proxy',
        // 配置jest測試環(huán)境,訪問組件的通配符,但是如果只是訪問ts文件,那么則無需要配置,只需要配置vite和tsconfig的配置即可
        '^~/(.*)': '<rootDir>/src/$1'
    },
  // 收集需要測試的 文件,支持匹配正則
  collectCoverageFrom:[],
  // 收集需要測試的文件有哪些,支持匹配正則
  testMatch:[]
}

cli

命令行運(yùn)行器jest有許多有用的選項(xiàng)。您可以運(yùn)行jest --help以查看所有可用選項(xiàng)。下面顯示的許多選項(xiàng)也可以一起使用,以完全按照您想要的方式運(yùn)行測試。Jest 的每個(gè)配置選項(xiàng)也可以通過 CLI 指定。說人話,就是為了看懂別人的寫法,因?yàn)樽约汉芏鄷r(shí)候直接就jest了。。。

從命令行運(yùn)行

查看: jest --help

運(yùn)行

  • jest 直接運(yùn)行
  • jest 路徑名 => 運(yùn)行的路徑是基于jest.config.js中的roots

例如:

roots: [
    "<rootDir>/src/_test/common"
],

那么我們執(zhí)行jest的時(shí)候執(zhí)行的是src/_test/common下面的test內(nèi)容,同時(shí)我們在運(yùn)行的時(shí)候執(zhí)行jest common/路徑名就相當(dāng)于是匹配到了/src/_test/common/路徑名

運(yùn)行與更改文件相關(guān)的測試: jest -o

他運(yùn)行的測試文件是運(yùn)行您本地沒有commit的jest文件,如果commit之后,jest -o執(zhí)行無效,并且會提示我們直接執(zhí)行jest或者執(zhí)行jest --all

jest命令支持駝峰和破折號

這就說明下面兩個(gè)效果是一樣,都表明更新快照,這個(gè)在測試react組件,組件內(nèi)容發(fā)生改變的時(shí)候使用

jest --update-snapshot
jest --updateSnapshot

參考reference

jest的命令行也有很多,但是絕大部分我們可能并不需要去關(guān)注,這里我以我自己常用的一些作為講解,如果工作中大家遇到了其它的配置,可以參考官網(wǎng)進(jìn)行查閱:
https://jestjs.io/docs/cli

// 打印jest配置信息并運(yùn)行,他同jest --showConfig有相同點(diǎn),不同的是debug還能繼續(xù)測試,而showConfig不會進(jìn)行測試
jest --debug

// 依次執(zhí)行test文件,默認(rèn)是創(chuàng)建一個(gè)測試的工作池
jest --runInBand   等同于jest -i

// 忽略測試文件中的打印信息,這個(gè)只需要了解,因?yàn)闇y試中的打印我們還是需要的
jest --silent   => jest -i --silent 實(shí)現(xiàn)單個(gè)測試+忽略測試文件打印

// 重新記錄在此測試運(yùn)行期間失敗的每個(gè)快照
jest --updateSnapshot 等同于jest -u

// 打印jest版本
jest --version

// 按照單個(gè)文件測試結(jié)果,輸出打印,對于調(diào)試比較有用,因?yàn)槟憧梢园l(fā)現(xiàn)是那塊出了問題
// 下面是jest和jest --verbose不同輸出打印的截圖
jest --verbose
verbose使用區(qū)別
// 打印jest的配置信息并推出
jest --showConfig

// 從指定路徑中找到的一個(gè)或多個(gè)項(xiàng)目運(yùn)行測試
// 但是這個(gè)貌似不太好用,因?yàn)楫?dāng)我們加上了projects之后,項(xiàng)目中配置的路徑別名就無法正確找到外部文件的引入了
jest --projects '路徑地址'

因此我們?nèi)粘9ぷ髦?,可能會這樣配置

{
    ...
    "scripts": {
        "test-dev": "jest",
        "test": "test --ci --runInBand --silent",
        "coverage": "jest --coverage --silent"
    }
}

看都看到這里了,幫幫忙點(diǎn)贊支持一波~

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容