引子
在之前分享的編輯器相關(guān)文章里饲齐,講到了語雀是全棧js開發(fā)的,并且號稱團(tuán)隊沒有測試工程師咧最,參考文章里面有放關(guān)于全棧 JavaScript 測試的相關(guān)總結(jié)分享捂人,今天我們就聊一聊前端的測試。
單元測試
- 定義:
在計算機(jī)編程中矢沿,單元測試(Unit Testing)又稱為模塊測試滥搭,是針對程序模塊(軟件設(shè)計的最小單位)來進(jìn)行正確性檢驗(yàn)的測試工作。
程序單元是應(yīng)用的最小可測試部件捣鲸。在過程化編程中瑟匆,一個單元就是單個程序、函數(shù)栽惶、過程等愁溜;對于面向?qū)ο缶幊蹋钚卧褪欠椒ㄍ獬Вɑ悾ǔ悾┟嵯蟆⒊橄箢悺⒒蛘吲缮悾ㄗ宇悾┲械姆椒ā?/p>
- 意義
- 提升能力
- 提升效率:及早發(fā)現(xiàn)問題
- 追求卓越:有助于開發(fā)人員去思考代碼結(jié)構(gòu)的設(shè)計汁蝶,讓代碼更加有利于測試
- 覆蓋全面:能夠覆蓋到QA測試覆蓋不到的情況
- 大型項(xiàng)目渐扮,協(xié)同開發(fā),公共抽離組件會出現(xiàn)一些問題掖棉,有了單測后墓律,更強(qiáng)壯,更易讀幔亥,升級時耻讽,回歸測試任務(wù)少,提升公共組件的質(zhì)量紫谷。
- 測試方法論 TDD&BDD
- TDD:Test-driven development 測試驅(qū)動開發(fā)
TDD 從測試的角度來檢驗(yàn)整個項(xiàng)目齐饮。大概的流程是先針對每個功能點(diǎn)抽象出接口代碼捐寥,然后編寫單元測試代碼,接下來實(shí)現(xiàn)接口祖驱,運(yùn)行單元測試代碼握恳,循環(huán)此過程,直到整個單元測試都通過捺僻。 - BDD:Behavior Driven Development 行為驅(qū)動開發(fā)
是通過編寫行為和規(guī)范來驅(qū)動軟件開發(fā)乡洼。更注重功能本身。
- 原則:FIRST
- F fast 快速 過程快
- I Isolate 隔離 測試用例應(yīng)當(dāng)獨(dú)立執(zhí)行匕坯,避免一個測試結(jié)果依賴于另外一個束昵。需要把測試分解成盡可能小的單元,這將幫我們確定在錯誤發(fā)生時的確切代碼位置葛峻。
- R Repeatable 可重復(fù):多次運(yùn)行測試應(yīng)該產(chǎn)生相同的結(jié)果锹雏,如果不確定,就不知道哪些結(jié)果是有效的术奖,哪些又是無效的礁遵。另外,反復(fù)性可以確保我們的測試不依賴于外部因素(諸如網(wǎng)絡(luò)或 CPU 負(fù)載)采记。
- S Self-validating 自我驗(yàn)證無需人工
- T Timely 及時佣耐,上線前
測什么
結(jié)果正確
邊界條件檢查
反向關(guān)聯(lián)(加密解密 讀寫操作)
強(qiáng)制錯誤條件測試的核心
斷言(assert)即表達(dá)程序設(shè)計人員對于系統(tǒng)應(yīng)達(dá)到狀態(tài)的一種預(yù)期。
前端測試框架:
幫助我們把測試代碼抽離出來唧龄,作為一個整體結(jié)構(gòu)化地去設(shè)計測試用例兼砖,放置到專門測試文件,然后也可以實(shí)現(xiàn)自動運(yùn)行以及顯示測試結(jié)果既棺。
介紹:
Mocha讽挟,Jest,Jasmine 可以說都是測試框架援制,可以達(dá)到之前說的戏挡,抽離,結(jié)構(gòu)化晨仑,自動運(yùn)行等等,其中 Jest 是一個相當(dāng)全面的框架拆檬,且零配置洪己,同時需要注意的是 Jest 也是基于 Jasmine 的,所以 Jest 的一些語法和 Jasmine 一模一樣竟贯,連報錯有時都會相同答捕。
Chai,Should 都屬于斷言庫屑那,它們的 API 相對測試框架自帶的斷言 API 更加語義化拱镐,更好用艘款,可以和上面的測試框架結(jié)合著用。
Karma 是一個 Test-Runner沃琅,可以說是凌駕測試框架之上哗咆,可以讓給你的瀏覽器自動跑所有的測試用例。
Enzyme是由airbnb開發(fā)的React單元測試工具益眉。它擴(kuò)展了React的TestUtils并通過支持類似jQuery的find語法可以很方便的對render出來的結(jié)果做各種斷言晌柬。
Jest
https://github.com/facebook/jest star 36.2k
Jest是Facebook開發(fā)的一個測試框架,它集成了測試執(zhí)行器郭脂、斷言庫年碘、spy、mock展鸡、snapshot和測試覆蓋率報告等功能屿衅。React項(xiàng)目本身也是使用Jest進(jìn)行單測的,因此契合度相當(dāng)高莹弊。
- 自帶斷言函數(shù)
exspect(運(yùn)行結(jié)果).toBe(期望的結(jié)果);
//常見斷言方法
expect({a:1}).toBe({a:1})//判斷兩個對象是否相等
expect(1).not.toBe(2)//判斷不等
expect({ a: 1, foo: { b: 2 } }).toEqual({ a: 1, foo: { b: 2 } })//判斷相等
expect(n).toBeNull(); //判斷是否為null
expect(n).toBeUndefined(); //判斷是否為undefined
expect(n).toBeDefined(); //判斷結(jié)果與toBeUndefined相反
expect(n).toBeTruthy(); //判斷結(jié)果為true
expect(n).toBeFalsy(); //判斷結(jié)果為false
expect(value).toBeGreaterThan(3); //大于3
expect(value).toBeGreaterThanOrEqual(3.5); //大于等于3.5
expect(value).toBeLessThan(5); //小于5
expect(value).toBeLessThanOrEqual(4.5); //小于等于4.5
expect(value).toBeCloseTo(0.3); // 浮點(diǎn)數(shù)判斷相等
expect('Christoph').toMatch(/stop/); //正則表達(dá)式判斷
expect(['one','two']).toContain('one'); //包含
- 支持異步測試
- 支持Dom測試
- Mock Functions
一個簡單的示例:
- 安裝
npm install --save-dev jest
- 新建測試文件
unit.test.js
import {dealData} from "./src/util/Util";
describe("dealData測試",()=>{
test('dealData 1 GB to equal 1 GB', () => {
expect(dealData(1, 'GB')).toEqual({
value:1,
unit:'GB'
});
});
//輸入數(shù)據(jù)大于1024GB則轉(zhuǎn)換為TB
test('dealData 2048 GB to equal 2 TB', () => {
expect(dealData(2048, 'GB')).toEqual({
value:2,
unit:'TB'
});
});
//輸入數(shù)據(jù)大于1024*1024*10GB則轉(zhuǎn)換為PB
test('dealData 20971520 GB to equal 20 PB', () => {
expect(dealData(20971520, 'GB')).toEqual({
value:20,
unit:'PB'
});
});
//PB為最大單位涤久,不進(jìn)行進(jìn)一步處理
test('dealData 419430400 GB to equal 20 PB', () => {
expect(dealData(41943040000, 'GB')).toEqual({
value:40000,
unit:'PB'
});
});
//其他單位不進(jìn)行轉(zhuǎn)換
test('dealData 1 KB to equal 1 KB', () => {
expect(dealData(1, 'KB')).toEqual({
value:1,
unit:'KB'
});
});
//接口異常時數(shù)據(jù)不進(jìn)行轉(zhuǎn)換
test('dealData -- to equal --', () => {
expect(dealData('--', '')).toEqual({
value:'--',
unit:''
});
});
})
注:dealData 是一個抽離出來的工具函數(shù),幫助動態(tài)處理業(yè)務(wù)數(shù)據(jù)單位
- 在
package.json
中增加代碼
{
"scripts": {
"test": "jest"
}
}
- 運(yùn)行
npm run test
image.png
Enzyme
https://github.com/enzymejs/enzyme star 19.7k
React測試必須使用官方的測試工具庫箱硕,但是它用起來不夠方便拴竹,所以有人做了封裝,推出了一些第三方庫剧罩,其中Airbnb公司的Enzyme最容易上手栓拜。
項(xiàng)目實(shí)戰(zhàn)時,結(jié)合jest和enzyme惠昔。
Enzyme為我們提供來三種渲染組件的方法shallow幕与、render、mount镇防。
shallow 方法就是官方的shallow rendering的封裝啦鸣。
render 方法將React組件渲染成靜態(tài)的HTML字符串,然后分析這段HTML代碼的結(jié)構(gòu)来氧,返回一個對象诫给。它跟shallow方法非常像,主要的不同是采用了第三方HTML解析庫Cheerio啦扬,它返回的是一個Cheerio實(shí)例對象中狂。
mount方法用于將React組件加載為真實(shí)DOM節(jié)點(diǎn)。
測試登錄交互例子:
import Login from 'pages/Login';
import React from 'react';
import { configure } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
import { mount } from 'enzyme';
configure({ adapter: new Adapter() });
const wrapper = mount(<Login />);
describe('', () => {
it('標(biāo)題顯示', () => {
const title = wrapper.find('.title').text();
expect(title).toBe('登錄');
})
const accountInput = wrapper.find('.account').find('input');
const accountTitle = wrapper.find('.account .name').find('span');
it('輸入不合法賬號', () => {
const event = {
target: {
value: 'abc123'
}
}
accountInput.simulate('change', event);
expect(accountTitle.text()).toBe('賬戶輸入錯誤扑毡,請重新輸入');
})
})
uirecorder
https://github.com/alibaba/uirecorder star 1.8k
UI Recorder 是一款面向多端的 UI 自動化錄制工具胃榕,類似于Selenium IDE 但比Selenium IDE 更加強(qiáng)大!
UI Recorder 非常簡單易用,零成本解決測試回歸問題瞄摊。
功能:
- 支持所有用戶行為: 鍵盤事件, 鼠標(biāo)事件, alert, 文件上傳, 拖放, svg, shadow dom
- 全平臺支持勋又,移動端 Android, iOS 錄制, 基于 Macaca 實(shí)現(xiàn)
- 無干擾錄制: 和正常測試無任何區(qū)別苦掘,無需任何交互
- 錄制用例存儲在本地
- 支持豐富的斷言類型: val,text,displayed,enabled,selected,attr,css,url,title,cookie,localStorage,sessionStorage
- 支持圖片對比
- 支持強(qiáng)大的變量字符串
- 支持公共測試用例: 允許用例中動態(tài)調(diào)用另外一個
- 支持并發(fā)測試
- 支持多國語言: 英文, 簡體中文, 繁體中文
- 支持單步截圖
- 支持HTML報告和JUnit報告
- 全系統(tǒng)支持: Windows, Mac, Linux
- 基于Nodejs的測試用例: jWebDriver
官方教程:https://www.yuque.com/artist/uirecorder/yd7ztf
- 初始化工程
- 開始錄制,進(jìn)行界面操作楔壤,可以添加斷言鹤啡,懸停等等
- 結(jié)束錄制,自動生成腳本文件
- 利用已有腳本文件進(jìn)行回歸測試