国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

前端自動化測試 —— Jest 測試框架應用

這篇具有很好參考價值的文章主要介紹了前端自動化測試 —— Jest 測試框架應用。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

目錄???????

什么是自動化測試

為什么要用前端自動化測試

前端自動化分類和思想

單元測試

集成測試

TDD 測試驅動開發(fā)(Test Driven Development)

BDD 行為驅動開發(fā)(Behavior Driven Development)

如何自己寫非框架測試用例

是否能簡化?

如何能清晰地看到我測的是哪個呢?

如何使用 Jest 測試框架進行自動化測試?

主流的前端自動化測試框架

Jasmine

MOCHA

Jest

準備工作 —— Jest 的配置

使用 babel 轉換來使用 ES6 形式的導入和導出

如何生成一個測試用例覆蓋率報告?

Jest 基礎匹配器

匹配器

命令行操作

異步測試

鉤子函數(shù)

分組方法 discribe

Mock

Mock 高階用法

Mock-timers

snapshot 快照

對 dom 節(jié)點測試

VSCode 插件

常用配置解讀

小結

代碼地址

參考文檔


什么是自動化測試

????????在軟件測試中,自動化測試指的是使用獨立于待測軟件的其他軟件來自動執(zhí)行測試、比較實際結果與預期并生成測試報告這一過程。在測試流程已經(jīng)確定后,測試自動化可以自動執(zhí)行的一些重復但必要的測試工作。也可以完成手動測試幾乎不可能完成的測試。對于持續(xù)交付和持續(xù)集成的開發(fā)方式而言,測試自動化是至關重要的。? ?——來自 WiKi 百科

為什么要用前端自動化測試

????????隨著前端項目的發(fā)展,其規(guī)模和功能日益增加。為了提高項目的穩(wěn)定性和可靠性,除了需要測試工程師外,前端自動化測試也成為了不可或缺的一環(huán)。采用前端自動化測試可以有效地提高代碼質量,降低出錯的概率,從而使項目更加健壯和更易維護。

前端自動化分類和思想

單元測試

????????又稱為模塊測試 ,是針對程序模塊(軟件設計的最小單位)來進行正確性檢驗的測試工作。在前端中,一個函數(shù)、一個類、一個模塊文件,都可以進行單元測試,測試時每個模塊都是互不干擾的。

前端自動化測試 —— Jest 測試框架應用

集成測試

????????是在單元測試的基礎上,測試再將所有的軟件單元按照概要設計規(guī)格說明的要求組裝成模塊、子系統(tǒng)或系統(tǒng)的過程中各部分工作是否達到或實現(xiàn)相應技術指標及要求的活動。用戶的開始操作到結束操作這一整個行為流程可以當作集成測試。

前端自動化測試 —— Jest 測試框架應用

TDD 測試驅動開發(fā)(Test Driven Development)

開發(fā)流程:

前端自動化測試 —— Jest 測試框架應用

TDD 是趨向于白盒測試,需要開發(fā)者對當前編寫的模塊思路足夠清晰。

優(yōu)勢:

  1. 長期減少回歸?bug

  2. 代碼質量更好,可維護性高。

  3. 測試覆蓋率高(先寫測試用例,再實現(xiàn)功能)。

  4. 錯誤測試代碼不容易出現(xiàn)(測試在開發(fā)之前執(zhí)行)。

BDD 行為驅動開發(fā)(Behavior Driven Development)

開發(fā)流程:

前端自動化測試 —— Jest 測試框架應用

BDD 趨向于黑盒測試,只關注用戶的一整套行為流程下來是否會成功。

優(yōu)勢:

  1. 對于用戶行為的整個流程把控程度較高,對于開發(fā)人員來說這樣安全感高。

如何自己寫非框架測試用例

????????不使用測試框架,我們該如何測試自己的模塊呢?如果我們想要測試下面的代碼,應該需要兩個值,一個是?期望值?,另一個是函數(shù)執(zhí)行的?結果值?,我們需要對比兩個值來進行判斷當前函數(shù)是否通過了測試用例。

//?index.js
function?ZcyZooTeam(str)?{
??return?'Zcy'?+?str;
}

????????需要下面的?if / else?進行判斷當前的期望值?value?和結果值?result?是否相等,如果相等說明我們的測試用例通過了。我們將這兩段代碼復制到瀏覽器中,下面的執(zhí)行不會通過,并會拋出錯誤,只有我們將傳入值改為?ZooTeam?才會成功執(zhí)行。

//?no-jest.js
const?result?=?ZcyZooTeam('Zero');
const?value?=?'ZooTeam';
if(result?!==?value)?{
??throw?Error(`ZcyZooTeam?結果應為${value},?但實際結果為${result}`);
}

前端自動化測試 —— Jest 測試框架應用

是否能簡化?

????????如果我們有多個函數(shù)需要測試,你應該不想寫許多個?if / else?代碼塊吧?所以我們要將上面的代碼塊進行優(yōu)化成一個函數(shù)。

//?no-jest.js
function?expect(result)?{
??return?{
????//?用于判斷是否為期望值
????toBe(value)?{
??????if(result?!==?value)?{
????????throw?Error(`結果應為${value},?但實際結果為${result}`);
??????}
??????console.log('測試通過!');
????}
??}
}

//?執(zhí)行測試
expect(ZcyZooTeam('Zero')).toBe('ZcyZooTeam');

經(jīng)過上面的封裝,我們就可以只寫一行代碼進行測試了!

如何能清晰地看到我測的是哪個呢?

????????雖然上面的封裝只需要書寫一行代碼就可以測試了,但是我們不知道執(zhí)行結果和測試用例之間的對應關系,我們需要輸出的文字來告訴我們當前是哪個測試用例執(zhí)行了。

//?no-jest.js
//?再封裝如下方法
function?test(msg,?fn)?{
??try?{
????fn();
????console.log(msg?+?'測試通過!');
??}?catch?(error)?{
????console.log(msg?+?'測試未通過!'?+?error);
??}
}

test('測試ZcyZooTeam',?()?=>?{
??expect(ZcyZooTeam('Zero')).toBe('ZcyZooTeam')
})

成功和失敗都會進行提示,這樣我們就可以知道當前是哪個測試用例成功/失敗了。

????Jest?的書寫方式也是同上,如果上面的一整套代碼了解了的話,你已經(jīng)可以寫?Jest?的測試腳本了,下面將進入?Jest?的配置。

如何使用 Jest 測試框架進行自動化測試?

主流的前端自動化測試框架

Jasmine

Jasmine?優(yōu)點:易于學習和使用,支持異步測試,可以在瀏覽器和?Node.js?環(huán)境中運行,可以生成易于閱讀的測試報告,可以與其他庫和框架集成。

MOCHA

MOCHA?優(yōu)點:支持異步測試和?Promise?,可以在瀏覽器和?Node.js?環(huán)境中運行,可以與其他庫和框架集成,可以生成易于閱讀的測試報告,可以使用各種插件和擴展來增強其功能。

Jest

Jest?是針對模塊進行測試,單元測試對單個模塊進行測試,集成測試對多個模塊進行測試。

Jest?優(yōu)點:速度快(單模塊測試時,執(zhí)行過的模塊不會重復執(zhí)行),API簡單,易配置,隔離性好(執(zhí)行環(huán)境相對隔離,每個文件單獨隔離互不干擾),監(jiān)控模式(更靈活的運行各種測試用例),適配編輯器多,Snapshot(快照),多項目運行(后臺前臺測試用例并行測試),生成可視化覆蓋率簡單,Mock?豐富。

準備工作 —— Jest 的配置

npm?i?jest?--save-D

//?初始化?jest?的配置文件
npx?jest?--init

//?你將在那個環(huán)境進行測試,回車即可選擇
//?第一個是?node?環(huán)境、第二個是瀏覽器環(huán)境
??Choose?the?test?environment?that?will?be?used?for?testing???-?Use?arrow-keys.?Return?to?submit.
????node
????jsdom?(browser-like)

//?是否需要?jest?生成測試覆蓋率報告
??Do?you?want?Jest?to?add?coverage?reports????(y/N)

//?是否需要在測試結束后清除模擬調用
??Automatically?clear?mock?calls?and?instances?between?every?test????(y/N)

//?創(chuàng)建?jest.config.js?文件
????Configuration?file?created?at?/Users/zcy1/Desktop/demo/auto-test-jest-demo/jest.config.js

????????以上方法執(zhí)行結束后,會生成一個?jest.config.js?文件,里面包含了?Jest?的配置項,每個配置項都會帶有描述,在初始化的兩個配置也會體現(xiàn)在配置文件中

使用 babel 轉換來使用 ES6 形式的導入和導出

//?.babelrc
//?如果想用?es6?的形式導出,需要使用?babel?插件進行轉換
//?@babel/core??@babel/preset-env

//?創(chuàng)建?.babelrc?文件
//?為了在?node?環(huán)境下使用?es6?的導出,需要使用?babel?進行轉換
{
??//?設置插件集合
??"presets":?[
????//?使用當前插件,可以進行轉換
????//?數(shù)組的第二項為插件的配置項
????[
??????"@babel/preset-env",?{
????????//?根據(jù)?node?的版本號來結合插件對代碼進行轉換
????????"targets":?{
??????????"node":?"current"
????????}
??????}
????]
??]
}

????????配置好后需要將?package.json?中的?test?命令的?value?改為?jest --watchAll,代表監(jiān)聽所有有修改的測試文件,然后控制臺執(zhí)行?npm run test?就可以執(zhí)行測試用例了。

Jest 啟動時會進行如下流程:

  1. ·npm run test

  2. ·jest (babel-jest)??檢測當前環(huán)境是否安裝了?babel

  3. ·如果安裝了則會去?babelrc?中取配置

  4. ·取到后執(zhí)行代碼轉換

  5. ·最后再執(zhí)行轉化過的測試用例代碼

如何生成一個測試用例覆蓋率報告?

經(jīng)過上面的?Jest?配置,我們就可以通過下面的?npx?命令來生成測試覆蓋率報告了

npx?jest?--coverage

????????會生成一個名為?coverage?的文件夾,打開里面的?html?就可以看到你的覆蓋率,其中?Statements?是語句覆蓋率(每個語句是否執(zhí)行),Branches?是分支覆蓋率(每個?if塊是否執(zhí)行),Functions是函數(shù)覆蓋率(每個函數(shù)是否執(zhí)行),Lines?是行覆蓋率(每行是否執(zhí)行),通過修改?coverageDirectory?的值可以改變測試覆蓋率生成文件夾的名字

Jest 基礎匹配器

????????上面我們說過了,Jest?的用法和我們封裝的那幾個函數(shù)是一樣的,都是執(zhí)行?test?函數(shù)并向函數(shù)中傳遞參數(shù),第一個參數(shù)是你當前測試用例的描述,第二個參數(shù)是需要執(zhí)行的匹配規(guī)則。

匹配器

toBe

toBe 匹配器,期待是否與匹配器中的值相等 相當于 object.is ===

//?jest.test.js
test("測試",?()?=>?{
??expect(1).toBe(1);??//?通過
??const?a?=?{?name:?'Zero'?};
??//?因為?a?的引用地址,和?toBe?中對象的引用地址不一致,會導致測試不通過,需要使用其他的匹配器
??expect(a).toBe({?name:?'Zero'?});??//?失敗
});

toEqual

toEqual 匹配器,只會匹配對象中的內容是否相等。

//?jest.test.js
test('測試對象相等',?()?=>?{
??const?a?=?{?name:?'Zero'?};
??expect(a).toEqual({?name:?'Zero'?});??//?斷言
})

toBeNull

toBeNull 匹配器,可以判斷變量是否為 null ,只能匹配 null。

//?jest.test.js
test('測試是否為null',?()?=>?{
??const?a?=?null;
??expect(a).toBeNull();
})

toBeUndefined

toBeUndefined 匹配器,可以判斷變量是否為 undefined ,只能匹配 undefined。

//?jest.test.js
test('測試是否為undefined',?()?=>?{
??const?a?=?undefined;
??expect(a).toBeUndefined();
})

toBeDefined

toBeDefined 匹配器,希望被測試的值是定義好的。

//?jest.test.js
test('測試變量是否定義過',?()?=>?{
??const?a?=?'';
??expect(a).toBeDefined();
})

toBeTruthy

toBeTruthy 匹配器,可以判斷變量是否為真值,會對非 bool 值進行轉換。

//?jest.test.js
test('測試變量真值',?()?=>?{
??const?a?=?'123';
??expect(a).toBeTruthy();
})

toBeFalsy

toBeFalsy 匹配器,可以判斷變量是否為假值,會對非 bool 值進行轉換。

//?jest.test.js
test('測試變量假值',?()?=>?{
??const?a?=?'';
??expect(a).toBeFalsy();
})

not修飾符

not 匹配器,可以將匹配后的結果進行取反。

//?jest.test.js
test('測試變量不是假值',?()?=>?{
??const?a?=?'1';
??expect(a).not.toBeFalsy();
})

toBeGreaterThan

toBeGreaterThan 匹配器,期望值是否大于匹配器的參數(shù)。

//?jest.test.js
test('是否大于?a?的數(shù)字',?()?=>?{
??const?a?=?123;
??expect(a).toBeGreaterThan(1);
})

toBeLessThan

toBeLessThan 匹配器,期望值是否小于匹配器的參數(shù)。

//?jest.test.js
test('是否小于?a?的數(shù)字',?()?=>?{
??const?a?=?0;
??expect(a).toBeLessThan(1);
})

toBeGreaterThanOrEqual

toBeGreaterThanOrEqual 匹配器,期望值是否大于或等于匹配器的參數(shù)。

//?jest.test.js
test('是否大于等于?a?的數(shù)字',?()?=>?{
??//?toBeLessOrEqual?匹配器,與之相反
??const?a?=?123;
??expect(a).toBeGreaterThanOrEqual(1);
})

toBeCloseTo

js 中,浮點數(shù)值在相加時不準確,使用 toBeCloseTo 匹配器解決,趨近于 0.3。

//?jest.test.js
test('是否大于等于?a?的數(shù)字',?()?=>?{
??const?a1?=?0.1;
??const?a2?=?0.2;
??expect(a1?+?a2).toBeCloseTo(0.3);
})

toMatch

toMatch 匹配器,匹配當前字符串中是否含有這個值,支持正則。

//?jest.test.js
test('是否包含?day?',?()?=>?{
??const?a?=?'happy?every?day';
??expect(a).toMatch('day');
})

toContain

toContain 匹配器,判斷當前數(shù)組中是否包含這個元素,Set 也可以使用。

//?jest.test.js
test('數(shù)組中是否包含?zoo?這個元素',?()?=>?{
??const?a?=?['zoo',?'ZooTeam',?'Zero'];
??expect(a).toContain('zoo');
})

toThrow

toThrow 匹配器,可以捕捉拋出的異常,參數(shù)為拋出的 error ,可以用來判斷是否為某個異常。

//?jest.test.js
const?error?=?()?=>?{
??throw?new?Error('error');
}
test('是否存在異常',?()?=>?{
??expect(error).toThrow();
})

????????以上就是?Jest?中比較基礎的匹配器,可以結合?初始化?+?配置?+?基礎匹配器?進行書寫測試用例。

命令行操作

????????在運行?npm run test?命令的時候,控制臺執(zhí)行測試用例成功或失敗后都會像下面的圖片一樣出現(xiàn)幾行提示,讓你按對應的鍵進行操作。

前端自動化測試 —— Jest 測試框架應用

上面幾個命令行的意思如下:

1.?f?只會跑測試未通過的用例,再次點擊 f 會取消當前模式。

? ? 我們使用一個失敗的測試用例做一下示范

前端自動化測試 —— Jest 測試框架應用

? ? 按下?f?后,Jest?只會執(zhí)行剛才失敗的測試用例

前端自動化測試 —— Jest 測試框架應用

2.?o?只監(jiān)聽已改變的文件,如果存在多個測試文件,可以開啟,會與當前 git 倉庫中的提交進行比較,需要使用 git 來監(jiān)聽哪個文件修改了,也可以將 --watchAll 改為 --watch 只會運行修改的文件。

3. 根據(jù)測試用例文件的正則表達式,過濾需要執(zhí)行的測試用例文件,No tests found, exiting with code 0?如果填寫不對會進行提示,并不會跑任何測試用例。

4. 根據(jù)測試用例描述的正則表達式,過濾需要執(zhí)行的測試用例。

5. 退出測試用例監(jiān)聽。

異步測試

????????在正常的業(yè)務開發(fā)中,項目中不只有同步代碼,還會有請求接口的異步代碼,異步代碼的測試與同步代碼有稍許不同,我們來看一下。

編寫一個接口請求

//?getData.js
export?const?getData?=?(fn)?=>?{
??axios.get('/getData').then((res)?=>?{
????fn(res.data);
??})
}

對異步請求進行測試

//?jest.test.js
//?異步調用回調函數(shù)需要添加?done?參數(shù),是一個函數(shù)
test('getData?返回結果為?{?success:?true?}',?(done)?=>?{
??//?此處代碼無效,因為測試用例不會等待請求結束后的回調,測試用例執(zhí)行完就直接結束了
??//?getData1((data)?=>?{
??//???expect(data).toEqual({
??//?????success:?true
??//???})
??//?})
??
??getData1((data)?=>?{
????expect(data).toEqual({
??????success:?true
????})
????//?需要在結束前調用?done?函數(shù),?Jest?會知道到?done?才會結束,才可以正確測試異步函數(shù)
????done();
??})
})

????????需要注意的是,如果傳入了形參?done,但是沒有使用,這個測試用例就會處于一直執(zhí)行的狀態(tài),直到執(zhí)行超時。

前端自動化測試 —— Jest 測試框架應用

還可以結合?promise?進行使用

//?getData.js
export?const?getData2?=?()?=>?{
??return?axios.get('http://www.dell-lee.com/react/api/demo.json')
}

//?jest.test.js
test('getData?返回結果為?{?success:?true?}',?()?=>?{
??//?使用?promise?時需要?return,在?then?中使用?done?也可以
??return?getData2().then(res?=>?{
????expect(res.data).toEqual({
??????success:?true
????})
??})
})

//?測試請求是否?404
test('getData?返回結果為?404',?()?=>?{
??//?由于不觸發(fā)?catch?就不會走測試校驗,所以會成功,我們需要做一下限制
??//?這行代碼限制下面的代碼中必須要執(zhí)行一次?expect?方法,
  // 如果非?404?就不會走下面的?expect,則測試不會通過
??expect.assertions(1);
??//?使用?promise?時需要?return
??//?如果只想測試?404?這樣寫是有問題的,需要配合?assertions?使用
??return?getData2().catch(err?=>?{
????expect(err.toString().indexOf('404')?>?-1).toBe(true)
??})
})

//?另一種寫法
test('getData?返回結果為?{?success:?true?}',?()?=>?{
??//?會返回很多數(shù)據(jù),其中包含?data?對象
??//?getData2().then((res)?=>?console.log(res))
??//?{
??//???status:?200,
??//???statusText:?'OK',
??//???headers:?{},
??//???......
??//???data:?{?success:?true?}
??//?}
??//?resolves?方法會將接口返回的字段全部獲取,再使用?toMatchObject?方法
  // 進行匹配大對象中是否存在?data?對象
??return?expect(getData2()).resolves.toMatchObject({
????data:?{
??????success:?true
????}
??})
})

//?還可以使用?async/await
test('getData?返回結果為?{?success:?true?}',?async?()?=>?{
??await?expect(getData2()).resolves.toMatchObject({
????data:?{
??????success:?true
????}
??})
})

鉤子函數(shù)

????????鉤子函數(shù)可以當作一個測試用例的生命周期來看待,有?beforeAll?、beforeEach?、afterEach?、afterAll?。

以下是一些關于鉤子函數(shù)的概念和場景:

? ? ? ? ·beforeAll:在所有測試用例執(zhí)行前運行

? ? ? ? ·beforeEach:在每個測試用例執(zhí)行前執(zhí)行一次

? ? ? ? ·afterEach:在每個測試用例執(zhí)行后執(zhí)行一次

? ? ? ? ·afterAll:在所有測試用例結束后運行

????????有時候,需要測試一個類中的多個方法,這些方法可能會反復操作同一個對象上的屬性。如果使用同一個實例,就會相互干擾,導致測試用例無法通過。此時,需要使用不同的實例來進行測試。

Counter 類

//?Counter.js
class?Counter?{
??constructor()?{
????this.number?=?0;
??}

??add()?{
????this.number?+=?1;
??}

??minus()?{
????this.number?-=?1;
??}
}

export?default?Counter;

????????我們想要測試里面的?add?和?minus?方法是否正確,需要實例化一個對象進行測試。但是下面的測試用例使用的永遠都是同一個實例,第二個測試用例永遠都不會通過。因為執(zhí)行了第一個測試用例,第二個測試用例的值只能是 0。

//?jest.test.js
const?count?=?new?Counter();
//?使用下方兩種測試方法會互相影響,先加一后減一,結果永遠是?0
test('測試加法',?()?=>?{
??count.add();
??expect(count.number).toBe(1);
})

test('測試減法',?()?=>?{
??count.minus();
??expect(count.number).toBe(-1);
})

需要使用鉤子函數(shù),在每次執(zhí)行測試用例的時候,都讓他重新實例化一個對象

//?jest.test.js
let?count?=?null;
//?類似于生命周期
//?會在測試用例執(zhí)行前運行
beforeAll(()?=>?{
??console.log('beforeAll')
});

//?會在每個測試用例執(zhí)行前執(zhí)行一次,這樣就會解決上面互相影響的問題
beforeEach(()?=>?{
??console.log('beforeEach')
??count?=?new?Counter();
});

//?會在每個測試用例執(zhí)行后執(zhí)行一次
afterEach(()?=>?{
??console.log('afterEach')
});

//?會在所有測試用例結束后運行
afterAll(()?=>?{
??console.log('afterAll');
});

test('測試加法',?()?=>?{
??console.log('add')
??count.add();
??expect(count.number).toBe(1);
})

test('測試減法',?()?=>?{
??console.log('minus')
??count.minus();
??expect(count.number).toBe(-1);
})

分組方法 discribe

//?jest.test.js
let?count?=?null;
//?describe?方法,可以將測試用例進行分組,更加好維護同類型功能的測試用例
describe('count?測試',?()?=>?{
??beforeAll(()?=>?{
????console.log('beforeAll')
??});
??beforeEach(()?=>?{
????console.log('beforeEach')
????count?=?new?Counter();
??});
??afterEach(()?=>?{
????console.log('afterEach')
??});
??afterAll(()?=>?{
????console.log('afterAll');
??});
??
??//?將?add?類型進行分組
??describe('測試?add?類型用例',?()?=>?{
????//?在?describe?方法中,鉤子函數(shù)會按照層級嵌套進行執(zhí)行,
    // 先執(zhí)行外部,再執(zhí)行內部,不同的?describe?互不干擾
????beforeEach(()?=>?{
??????console.log('beforeEach?add');
????});
????test('測試加法',?()?=>?{
??????console.log('add')
??????count.add();
??????expect(count.number).toBe(1);
????})
??})

??//?將?minus?類型進行分組
??describe('測試?minus?類型用例',?()?=>?{
????test('測試減法',?()?=>?{
??????console.log('minus')
??????count.minus();
??????expect(count.number).toBe(-1);
????})
??})
})

加上?describe?方法的執(zhí)行效果如下圖。

前端自動化測試 —— Jest 測試框架應用

Mock

????????在日常開發(fā)中,當前端開發(fā)差不多后,后端接口可能還沒有提供,這個時候我們就要用?Mock?數(shù)據(jù)。而?Jest?也有?Mock?方法,用于模擬一些?JavaScript?的函數(shù)等。

我們先來一個比較簡單的?mock.fn

//?mock.js
export?const?runFn?=?(fn)?=>?{
??fn(123);
}

//?mock.test.js
test('測試?runFn',?()?=>?{
??//?通過?jest?的?fn?方法創(chuàng)建一個模擬函數(shù),如果不傳參數(shù)會默認生成一個函數(shù)
??//?1.?通過?func.mock?獲取想要的值
??//?2.?可以自定義返回值
??//?3.?改變內部函數(shù)的實現(xiàn),模擬接口請求,不請求代碼中的接口
??const?func?=?jest.fn(?()?=>?456?);

??//?還可以使用?mockReturnValueOnce?方法進行控制輸出,
  // 兩種方法都使用時會覆蓋?fn?方法中的返回值,支持鏈式調用
??//?將?Once?去掉與?fn?方法一樣,多次會返回相同的值
??func.mockReturnValueOnce('zoo')

??//?返回?this?方法?mockReturnThis
??func.mockReturnThis();

??//?還可以使用?mockImplementation?方法書寫函數(shù)內部,可以在函數(shù)內部寫邏輯,
  // 與?jest.fn?方法的參數(shù)一樣,還可以填加?Once
??func.mockImplementation(()?=>?{
????return?'123';
??})

??//?執(zhí)行被測函數(shù)
??runFn(func);
??runFn(func);
??
??//?console.log(func.mock)
??//?因為被調用了兩次,所以長度都是?2
??//?{
??//???calls:?[?[123],?[123]?],??//?每次的調用情況,傳遞的參數(shù)是什么
??//???instances:?[?undefined,?undefined?],??//?每次調用的?this?指向,被調用了幾次
??//???invocationCallOrder:?[?1,?2?],??//?執(zhí)行順序,
  //   可能會傳入同一個或多個方法中,需要記錄一下順序
??//???results:?[??//?mock?函數(shù)每次執(zhí)行后的返回值
??//?????{?type:?'return',?value:?456?},
??//?????{?type:?'return',?value:?456?}
??//???]
??//?}

??//?通過?toBeCalled?判斷函數(shù)是否被調用
??expect(func).toBeCalled();

??//?判斷當前函數(shù)調用了幾次?被調用了兩次
??expect(func.mock.calls.length).toBe(2);

??//?判斷參數(shù)是什么
??expect(func.mock.calls[0]).toEqual([123]);

??//?判斷每次調用的時候參數(shù)是什么
??expect(func).toBeCalledWith(123);

??//?判斷返回值
??expect(func.mock.results[0].value).toBe('zoo');
})

Mock 高階用法

????????如果需要通過修改請求的方式進行測試,而不使用測試框架,我們可能需要修改請求的代碼邏輯。但是,Jest?提供了一種高級的?Mock?方法。我們只需在項目根目錄下創(chuàng)建一個名為?__mocks__?的文件夾,然后在其中自定義文件內容并導出,就可以使用自己定義的?Mock?函數(shù)而不必修改請求代碼邏輯。

前端自動化測試 —— Jest 測試框架應用

書寫測試用例文件,引入?__mocks__?文件夾中的函數(shù)

//?mocker.test.js
//?使用?mock?方法引用?__mocks__?下創(chuàng)建的?mock.js
jest.mock("./mock");
//?執(zhí)行完上面的方法,會直接尋找?__mocks__?下的getData,而不是正常的請求文件
//?由于?mock?中沒有?getCode?方法,最好只?mock?異步函數(shù),同步函數(shù)直接測試即可
//?可以不必須創(chuàng)建?__mocks__?文件夾
import?{
??getData,
}?from?"./mock";

//?需要使用下面的?requireActual?方法來引用非?mock?文件夾下的?getCode
const?{?getData?}?=?jest.requireActual("./mock");

//?高階mock
//?此處直接使用?__mocks__?目錄下的?mock?文件中的函數(shù)
test("測試?getData",?()?=>?{
??return?getData().then((data)?=>?{
????expect(eval(data)).toEqual("123");
??});
});

Mock-timers

????????在特定的業(yè)務中,需要使用到定時器,測試的時候也是需要修改代碼來測試不同時間,最主要的一點是,我們需要等時間才能看到我們的執(zhí)行結果,Jest?也有關于定時器的?Mock函數(shù)。

//?mock.js
export?const?timer?=?(fn)?=>?{
??setTimeout(()?=>?{
????fn();
????setTimeout(()?=>?{
??????fn();
????},?3000)
??},?3000)
}
//?mock-timers.test.js
import?{?timer?}?from?'./mock';

//?使用?useFakeTimers?方法告知?Jest?在下面的測試用例,
// 如果用到了定時器異步函數(shù)的時候,都是用假的?timers?進行模擬
jest.useFakeTimers();

test('測試?timer',?()?=>?{
??const?fn?=?jest.fn();
??timer(fn);

??//?使用?runAllTimers?方法,讓定時器立即執(zhí)行,和?useFakeTimers?配合使用
??jest.runAllTimers();

??//?如果代碼中有多個定時器嵌套,只想測試最外層的定時器,則需要使用?runOnlyPendingTimers?方法
??//?這個方法會只執(zhí)行當前在隊列中的函數(shù),可以多次調用
??jest.runOnlyPendingTimers();
??jest.runOnlyPendingTimers();

??//?advanceTimersByTime?方法,可以快進時間
??//?因為?timer?中,三秒后只執(zhí)行了第一層,如果是六秒,則會執(zhí)行兩次?fn
??jest.advanceTimersByTime(3000);
})

snapshot 快照

????????到這里我們已經(jīng)可以測試一些代碼了,但是我們要如何捕捉執(zhí)行結果和當前做對比呢?這時候就要使用快照功能了。

//?snapshot.js
export?const?config1?=?()?=>?{
??return?{
????method:?'GET',
????url:?'/api',
????time:?new?Date()
??}
}

export?const?config2?=?()?=>?{
??return?{
????method:?'GET',
????url:?'/api',
????time:?new?Date().getTime()
??}
}
//?snapshot.test.js
import?{?config1,?config2?}?from?"./snapshot";

test('測試?config1?返回值',?()?=>?{
??//?但如果每次函數(shù)修改的時候,當前測試用例也要不斷地修改
??//?expect(config()).toEqual({
??//???method:?'GET',
??//???url:?'/api'
??//?});

??//?需要使用快照匹配?toMatchSnapshot?方法
??//?此方法會生成一個?__snapshots__?目錄,下面的文件中,
  // 第一次執(zhí)行中?config?生成的結果會存到快照文件中
??//?快照會根據(jù)?test?方法中的描述生成一個映射關系
??//?修改后的?config?的執(zhí)行結果與快照中的結果不同時會報錯,需要更新快照
??//?如果?config?中有的值是每次運行都會變化的,那么每次快照都不會與當前執(zhí)行相同,
  // 除非執(zhí)行后再更新快照
??//?需要將在?toMatchSnapshot?方法中傳遞一個參數(shù),設置一下?time?為任意格式的?Date?類型
??expect(config1()).toMatchSnapshot({
????time:?expect.any(Date)
??});
})

test('測試?config2?返回值',?()?=>?{
??expect(config2()).toMatchSnapshot({
????time:?expect.any(Number)
??});
})

行內快照生成

//?snapshot.test.js
//?需要安裝?prettier
test("測試?config2?返回值",?()?=>?{
??//?toMatchInlineSnapshot?方法,將執(zhí)行快照放到行內中,
  // 會放到?toMatchInlineSnapshot?方法中
??expect(config2()).toMatchInlineSnapshot(
????{
??????time:?expect.any(Number)
????},
????`
????Object?{
??????"method":?"GET",
??????"time":?Any<Number>,
??????"url":?"/api",
????}
??  `
??);
});

對 dom 節(jié)點測試

????Jest?內部自己模擬了一套?jsDom?,可以在?node?的環(huán)境下執(zhí)行需要瀏覽器環(huán)境?dom的測試用例。

//?dom.js
import?$?from?'jquery';
const?addDiv?=?()?=>?{
??//?jQuery
??$('body').append('<div/>');
}

export?default?addDiv;

//?dom.test.js
import?addDiv?from?'./dom';
import?$?from?'jquery';

test('測試?addDiv',?()?=>?{
??addDiv();
??addDiv();
??console.log($('body').find('div').length);

??//?測試dom
??expect($('body').find('div').length).toBe(2);
??expect(document.getElementsByTagName('div').length).toBe(2);
})

VSCode 插件

????Jest Snippets?用于快速生成?Jest?代碼塊的工具。

????Jest?能夠檢測當前文件夾中的測試用例并自動運行測試,還支持可視化操作,更新、執(zhí)行以及單個執(zhí)行等功能,非常方便!

常用配置解讀

module.exports?=?{
??//?檢測從哪個目錄開始,rootDir?代表根目錄
??roots:?["<rootDir>/src"],

??//?代碼測試覆蓋率通過分析那些文件生成的,!代表不要分析
??collectCoverageFrom:?[
????//?src?下所有?js?jsx?ts?tsx?后綴的文件
????"src/**/*.{js,jsx,ts,tsx}",

????//?src?下所有?.d.ts?后綴的文件
????"!src/**/*.d.ts"
??],

??//?運行測試之前,我們額外需要準備什么
??setupFiles:?["react-app-polyfill/jsdom"],

??//?當測試環(huán)境建立好后,需要做其他事情時可以引入對應的文件
??setupFilesAfterEnv:?["<rootDir>/src/setupTests.js"],

??//?哪些文件會被認為測試文件
??testMatch:?[
????//?src?下的所有?__tests__?文件夾中的所有的?js?jsx?ts?tsx?后綴的文件都會被認為是測試文件
????"<rootDir>/src/**/__tests__/**/*.{js,jsx,ts,tsx}",

????//?scr?下的所有一?.test/spec.js/jsx/ts/tsx?后綴的文件都會被認為是測試文件
????"<rootDir>/src/**/*.{spec,test}.{js,jsx,ts,tsx}",
??],

??//?測試運行的環(huán)境,會模擬?dom
??testEnvironment:?"jsdom",

??//?測試文件中引用一下后綴結尾的文件會使用對應的處理方式
??transform:?{
????//?如果引用的是?js?jsx?mjs?cjs?ts?tsx?后綴的文件會使用?/config/jest/babelTransform.js?文件進行處理
????"^.+\\.(js|jsx|mjs|cjs|ts|tsx)$":?"<rootDir>/config/jest/babelTransform.js",

????//?如果引用的是?css?后綴的文件,會使用?/config/jest/cssTransform.js?文件處理
????"^.+\\.css$":?"<rootDir>/config/jest/cssTransform.js",

????//?不是以?js?jsx?mjs?cjs?ts?tsx?css?json?這些為后綴的文件會使用?/config/jest/fileTransform.js?文件進行處理
????"^(?!.*\\.(js|jsx|mjs|cjs|ts|tsx|css|json)$)":
??????"<rootDir>/config/jest/fileTransform.js",
??},

??//?忽略?transform?配置轉化的文件
??transformIgnorePatterns:?[
????//?node_modules?目錄下的?js?jsx?mjs?cjs?ts?tsx?后綴的文件都不需要轉化
????"[/\\\\]node_modules[/\\\\].+\\.(js|jsx|mjs|cjs|ts|tsx)$",

????//?.module.css/sass/scss?后綴的文件都不需要轉化
????"^.+\\.module\\.(css|sass|scss)$",
??],

??//?自動化測試時,應用的模塊應該從哪里尋找,默認是在?node_modules
??modulePaths:?[],

??//?模塊名字使用哪種工具進行映射
??moduleNameMapper:?{
????//?針對于?native?移動端
????//?"^react-native$":?"react-native-web",

????//?將?.module.css/sass/scss?模塊使用?identity-obj-proxy?工具進行轉化
????"^.+\\.module\\.(css|sass|scss)$":?"identity-obj-proxy",
??},

??//?引入模塊時,進行自動查找模塊類型,逐個匹配
??moduleFileExtensions:?[
????"web.js",
????"js",
????"web.ts",
????"ts",
????"web.tsx",
????"tsx",
????"json",
????"web.jsx",
????"jsx",
????"node",
??],

??//?監(jiān)聽插件
??watchPlugins:?[
????"jest-watch-typeahead/filename",
????"jest-watch-typeahead/testname",
??],

??//?重置?mock
??resetMocks:?true,
};

小結

????????在實際業(yè)務應用中,我們建議對可復用的組件、工具函數(shù)、工具類等一些無副作用,可預知結果的代碼來進行單元測試。在前期開發(fā)過程中的投入會大于沒有單元測試的投入,因為要寫一些測試用例,還要執(zhí)行測試用例,優(yōu)化代碼等。但是在長久迭代中,這種方法會比沒有進行單元測試的模塊更加穩(wěn)定。

代碼地址

  1. 前置?demo?:https://github.com/Jadony/Jest-demo

  2. Jest?簡單配置:https://github.com/Jadony/jest-config

  3. Jest?匹配器:https://github.com/Jadony/jest-matchers

  4. 異步代碼測試:https://github.com/Jadony/jest-async

  5. Jest?鉤子函數(shù):https://github.com/Jadony/jest-hook

  6. Jest?的?mock?函數(shù):https://github.com/Jadony/jest-mock

  7. Jest?的快照:https://github.com/Jadony/jest-snapshot

  8. Jest?對?Dom?節(jié)點的測試:https://github.com/Jadony/jest-dom

參考文檔

  • 《前端要學的測試課 從Jest入門到TDD/BDD雙實戰(zhàn)》(https://coding.imooc.com/class/chapter/372.html#Anchor)

????????如果想學習更多內容,請移步至 Jest(https://jestjs.io/zh-Hans/docs/getting-started) 官方文檔。文章來源地址http://www.zghlxwxcb.cn/news/detail-466652.html

到了這里,關于前端自動化測試 —— Jest 測試框架應用的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。如若轉載,請注明出處: 如若內容造成侵權/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領支付寶紅包贊助服務器費用

相關文章

  • 前端自動化測試框架-Cypress

    前端自動化測試框架-Cypress

    一提起 Web UI 自動化時,大多數(shù)都會想到自動化測試工具 Selenium。隨著測試技術的不斷發(fā)展,出現(xiàn)了很多優(yōu)秀的自動化測試工具。 本篇將介紹一款目前市面上很受歡迎的自動化測試工具-Cypress。 Cypress 是一個易于使用、快速穩(wěn)定、可靠性高、全面性強的自動化測試框架,因此

    2024年02月10日
    瀏覽(18)
  • vue3配置jest自動化測試

    vue3配置jest自動化測試

    前排提醒,并不是所有的項目都需要單元測試,因為寫單元測試真的很耗時間。單元測試主要針對需求變更不多,項目時間充裕的項目。如elementui這種框架類的項目 本文主要針對vue3+vuecli4 這里主要有兩種情況:新建項目和老項目 對于新建項目,在通過腳手架生成時可選擇

    2024年02月12日
    瀏覽(21)
  • 【自動化測試】幾種常見的自動化測試框架

    【自動化測試】幾種常見的自動化測試框架

    在軟件測試領域,自動化測試框架有很多,這里主要介紹幾種常用的自動化測試框架。 pytest 是 Python 的一種單元測試框架,與 Python 自帶的 unittest 測試框架類似,但是比 unittest 框架使用起來更簡潔,效率更高。主要有以下幾個特點: 簡單靈活,容易上手。 支持參數(shù)化。 能

    2024年02月07日
    瀏覽(21)
  • 自動化測試(三):接口自動化pytest測試框架

    自動化測試(三):接口自動化pytest測試框架

    API:Application Programming Interface 接口自動化按照自動化的工具可分為 基于 接口測試工具 的接口自動化 eg1:Postman+Newman+git/Svn+Jenkins(基于Javascript語言)接口自動化 Postman :創(chuàng)建和發(fā)送 API 請求,并對響應進行斷言和驗證。 Newman : Postman 的命令行工具,它允許測試人員在沒有界

    2024年02月10日
    瀏覽(94)
  • 從0到1精通自動化測試,pytest自動化測試框架,doctest測試框架(十四)

    從0到1精通自動化測試,pytest自動化測試框架,doctest測試框架(十四)

    doctest從字面意思上看,那就是文檔測試。doctest是python里面自帶的一個模塊,它實際上是單元測試的一種。 官方解釋:doctest 模塊會搜索那些看起來像交互式會話的 Python 代碼片段,然后嘗試執(zhí)行并驗證結果 doctest測試用例可以放在兩個地方 函數(shù)或者方法下的注釋里面 模塊的

    2024年02月11日
    瀏覽(91)
  • 自動化測試介紹、selenium用法(自動化測試框架+爬蟲可用)

    自動化測試介紹、selenium用法(自動化測試框架+爬蟲可用)

    1、什么是自動化測試? 程序測試程序、代碼代替思維、腳本代替人工 核心:質量和效率 作用:降低成本、節(jié)省人力時間、推動CI和DevOps、準確性和可靠性、模擬人工難以實現(xiàn)的手段、快速持續(xù)迭代發(fā)布能力、衡量產(chǎn)品的質量、提升測試效率、提高測試覆蓋率 2、手工測試

    2024年03月08日
    瀏覽(39)
  • python自動化測試- 自動化框架及工具

    python自動化測試- 自動化框架及工具

    手續(xù)的關于測試的方法論,都是建立在之前的文章里面提到的觀點: 功能測試不建議做自動化 接口測試性價比最高 接口測試可以做自動化 后面所談到的? 測試自動化 ?也將圍繞著? 接口自動化 ?來介紹。 本系列選擇的測試語言是 python 腳本語言。由于其官方文檔已經(jīng)對原理

    2024年02月22日
    瀏覽(32)
  • Pytest自動化測試框架---(單元測試框架)

    Pytest自動化測試框架---(單元測試框架)

    unittest是python自帶的單元測試框架,它封裝好了一些校驗返回的結果方法和一些用例執(zhí)行前的初始化操作,使得單元測試易于開展,因為它的易用性,很多同學也拿它來做功能測試和接口測試,只需簡單開發(fā)一些功能(報告,初始化webdriver,或者http請求方法)便可實現(xiàn)。 但自

    2024年02月14日
    瀏覽(120)
  • UI自動化概念+Web自動化測試框架

    UI自動化概念+Web自動化測試框架

    1.UI自動化測試概念:我們先明確什么是UI UI,即(User Interface簡稱UI用戶界面)是系統(tǒng)和用戶之間進行交互和信息交換的媒介 UI自動化測試: Web自動化測試和移動自動化測試都屬于UI自動化測試,UI自動化測試就是借助自動化工具對程序UI層進行自動化的測試 2.為什么對UI采用自動化

    2024年02月06日
    瀏覽(94)
  • Selenium+python怎么搭建自動化測試框架、執(zhí)行自動化測試用例、生成自動化測試報告、發(fā)送測試報告郵件

    Selenium+python怎么搭建自動化測試框架、執(zhí)行自動化測試用例、生成自動化測試報告、發(fā)送測試報告郵件

    本人在網(wǎng)上查找了很多做自動化的教程和實例,偶然的一個機會接觸到了selenium,覺得非常好用。后來就在網(wǎng)上查閱各種selenium的教程,但是網(wǎng)上的東西真的是太多了,以至于很多東西參考完后無法系統(tǒng)的學習和應用。 以下整理的只是書中自動化項目的知識內容,介紹怎么搭

    2024年02月05日
    瀏覽(30)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領取紅包,優(yōu)惠每天領

二維碼1

領取紅包

二維碼2

領紅包