W3Cschool
恭喜您成為首批注冊用戶
獲得88經(jīng)驗值獎勵
測試是軟件開發(fā)中必不可少的一個環(huán)節(jié),程序化測試能夠加快研發(fā)速度,提高協(xié)作效率,減少產(chǎn)品故障。
通過本節(jié),你將學(xué)會:
傳統(tǒng)前端項目的測試,可以從兩個維度去做分類:
從粗細粒度的角度看,測試分為以下幾類:
主要針對JS中的某些方法(不包括ux中的定義),這些方法獨立性強,不強依賴于外部環(huán)境;
這類需求有明確的輸入輸出要求,通過常規(guī)的測試框架即可完成,如:mocha、Jest;
主要針對功能比較完整的模塊或者組件,它們是多個單元/模塊的組裝與業(yè)務(wù)結(jié)合;
這類需求希望面對常見的業(yè)務(wù)應(yīng)用場景,能夠得到正確的界面渲染與數(shù)據(jù)結(jié)構(gòu);
在當前的快應(yīng)用平臺中,如果用到自定義組件或者底層接口(如:@system.fetch),需要依賴于真機環(huán)境進行測試確認結(jié)果;
當然,部分開發(fā)者希望能夠提供一個模擬環(huán)境(如:NodeJS)的快應(yīng)用平臺,方便在PC上完成測試,目前這個能力僅團隊內(nèi)部使用,考慮到更新頻次較高,暫沒有對外開放;
實際上,優(yōu)先推薦開發(fā)者使用真機環(huán)境通過自動化的方式完成確認,這樣可以確保多手機廠商設(shè)備下對功能的統(tǒng)一能力確認;
針對這類測試的實現(xiàn),開發(fā)者可以考慮在快應(yīng)用項目中建立新的能力測試頁面,引入待測試的自定義組件與模塊,通過?mocha
?、?Jest
?等工具完成斷言;
主要針對項目與頁面級別的測試,確保項目的基本功能暢通,是對項目上線的一個主要保障;
這類需求的原理就是通過真實的瀏覽器去運行每個頁面,模擬用戶行為操作,確保界面的一致性,功能正確;
對于WEB的前端開發(fā)者通過?Karma
?、?Selenium
?等工具,完成對瀏覽器操作的自動化封裝,最終測試頁面與后端服務(wù)器的正確配合;
對于快應(yīng)用的前端開發(fā)者,需要借助于一些接口與簡單類庫封裝,來承載頁面的加載、切換等測試任務(wù);
從功能覆蓋的角度,測試可以分為幾類:
主要針對底層為前端開發(fā)者提供的接口,確保這些接口在跨設(shè)備上行為和輸出正確;如:?@system.storage
?;
主要針對頁面局部的UI布局渲染正確,確定:文本、對話框、滑動等節(jié)點存在,位置正確;
主要針對某些行為操作下的功能表現(xiàn)正確,或者小到一個模塊、一個方法的輸出正確;
在快應(yīng)用的項目中,如果開發(fā)者僅僅只是JS文件中方法的單元測試的話(不需要引入底層接口),完全可以通過自己引入?mocha
?等工具,然后運行在PC的NodeJS環(huán)境來實現(xiàn),這塊實現(xiàn)簡單,本文不贅述;
當前快應(yīng)用的實現(xiàn)中,框架為開發(fā)者提供了一套e2e的測試框架,這類測試需要運行在真實的手機設(shè)備中,然后配合?@system.router
?接口完成頁面之間的切換與內(nèi)容測試,后面介紹原理;
開發(fā)者可以通過以下步驟來為項目引入e2e的測試能力(當前使用的?hap-toolkit
?工具版本為:?0.6.8
?);
使用命令行新建一個自定義項目,名稱為:?quickapp-demo-quality
?
npx hap init quickapp-demo-quality
當前,開發(fā)者也可以使用自己已有的項目,用于增加測試能力;
提示:為了方便開發(fā)者理解并使用,快應(yīng)用官方的 Github站點 提供了 示例項目 ;
在項目中,創(chuàng)建?test
?目錄,與?src
?目錄同級,該文件夾用于存放所有的頁面測試用例;
其中針對每個頁面的測試用例的文件路徑需要與?src
?目錄中對應(yīng)頁面的路徑保持一致;
當前項目我們添加?Demo
?、?DemoDetail
?、?About
?三個頁面的測試用例。結(jié)構(gòu)如下:
其中針對?Demo
?頁面的測試用例,舉例如下,其它測試用例的文件內(nèi)容類似:
/**
* @param vm 代表頁面的ViewModel實例
*/
export default function(vm) {
// 其中describe, it, expect函數(shù)來自于對 mocha, chai的引入;
describe(`Demo`, function() {
it(`測試Detail頁面vm屬性`, function(done) {
expect(2).to.equal(3)
done()
})
it(`測試Detail頁面vm方法`, function(done) {
done()
})
})
}
在?test
?目錄下創(chuàng)建一個JS文件?autocase.js
?,表示所有要測試的頁面文件列表,其內(nèi)容如下:
代碼中描述了本次要測試的頁面為:?Demo
?、?DemoDetail
?、?About
?;
const autoCaseList = [
'Demo',
'DemoDetail',
'About'
]
export {
autoCaseList
}
該文件供下面的測試匯總頁面使用,聲明哪些頁面需要進行?e2e
?測試。
上一步僅代表哪些頁面需要進行測試,并測試頁面中的哪些能力;
這一步主要完成兩件事:
1) 增加測試匯總頁面,記錄測試結(jié)果;
2) 將各測試頁面的結(jié)果與切換連接起來,形成自動化;
在?src
?目錄下創(chuàng)建一個測試匯總的頁面?Summary
?并在?manifest.json
?中聲明路由;
頁面內(nèi)容中的JS代碼部分舉例如下:
<script>
import router from '@system.router'
import {
autoCaseList
} from '../../test/autocase'
/**
* 獲取下一個自動測試的page
*/
function findNextTestPage() {
const list = global.loadData('pageNameList')
const item = list.shift()
global.saveData('pageNameList', list)
return item
}
function waitForOK(time = 100) {
return new Promise(resolve => {
setTimeout(resolve, time)
})
}
export default {
private: {
// 包含自動測試腳本的case列表
pageNameList: [],
pageTestList: [],
shouldTestAll: false,
showCompletedText: false,
isRunningTest: false
},
onInit() {
this.pageNameList = autoCaseList
// 初始化自動化測試相關(guān)數(shù)據(jù)
if (global.loadData) {
global.saveData('pageNameList', this.pageNameList)
}
},
onShow() {
// 更新pageTestList
this.pageTestList = (global.loadData('pageTestList') || []).map(item => {
item.showPageTestDetail = false
item.tests.forEach(itemCase => {
itemCase.showPageTestErrDetail = false
})
return item
})
this.shouldTestAll && this.startNextTestPage()
},
/**
* 重啟整個所有測試
*/
restartTestProcess() {
// 防止連續(xù)多次點擊
if (!this.isRunningTest) {
this.isRunningTest = true
global.saveData('pageNameList', this.pageNameList)
global.saveData('pageTestList', [])
// 重置測試結(jié)束文本的顯示狀態(tài)
this.showCompletedText = false
// 自動跑測試下一個測試用例
this.shouldTestAll = true
// 啟動下個測試用例
this.startNextTestPage()
}
},
/**
* 啟動下個測試用例
*/
async startNextTestPage() {
const pageItem = findNextTestPage()
console.info(`下個測試用例:${pageItem}`)
if (pageItem) {
await waitForOK(1000)
console.info(`開始測試頁面:${pageItem}`)
router.push({
uri: pageItem
})
} else {
this.isRunningTest = false
console.info(`測試用例列表執(zhí)行完畢`)
this.showCompletedText = true
this.shouldTestAll = false
}
},
gotoPage(path, params) {
// 單個頁面的點擊跳轉(zhuǎn):不會在測試后,自動返回
params = Object.assign({
back: 'false'
}, params)
router.push({
uri: path,
params
})
},
togglePageTestDetailStatus($item) {
$item.showPageTestDetail = !$item.showPageTestDetail
},
togglePageErrStackStatus($item) {
$item.showPageTestErrDetail = !$item.showPageTestErrDetail
}
}
</script>
提示:開發(fā)者可以在 官方站點的示例項目 中查看 該頁面全部內(nèi)容 ,路徑為:src/Summary/index.ux
在項目目錄下,執(zhí)行構(gòu)建命令 ?npm run build:test
?,并運行在快應(yīng)用平臺,即可完成自動化測試;
掃碼打開頁面并點擊按鈕?點擊重新測試
?,完成一整套自動化測試過程。
最終的示例效果如下:
上面這種e2e的測試方式,并不需要修改框架運行時,即:不需要前端框架配合修改某些代碼;
相反,它的實現(xiàn)主要是通過:上面的開發(fā)者代碼與?hap-toolkit
?編譯時工具在啟用參數(shù)?--enable-e2e
?構(gòu)建后注入的代碼配合完成的;
下面從編譯時、運行時兩個方面,介紹實現(xiàn)原理,方便開發(fā)者理解,并進行更深程度的定制與改造;
npm run build:test
?,將會啟用參數(shù)?--enable-e2e
?來創(chuàng)建RPK文件;開發(fā)者可以通過?package.json
?查看細節(jié);hap-toolkit
?將會完成以下幾件事,其中前兩步可以通過?build/app.js
?文件查看細節(jié),后兩部通過?build
?目錄下對應(yīng)的頁面JS查看細節(jié);app.ux
?中,注入測試相關(guān)類庫:?hybrid-mocha
?、?hybrid-chai
?,他們分別是對類庫?mochajs
?、?chaijs
?的簡單適配的封裝;app.ux
?中,注入一些全局函數(shù):?loadData(key)
?、?saveData(key, value)
?提供給每個頁面調(diào)用,這兩個函數(shù)分別用于向JS內(nèi)存中全局獲取數(shù)據(jù)與保存數(shù)據(jù);test
?目錄中對應(yīng)的測試用例文件(相對路徑保持一致的JS文件);mocha
?實例化與運行的代碼,偽代碼如:?const mocha = new Mocha(); mocha.run();
?;hap-toolkit
?走正常流程,編譯每個頁面,如:?匯總頁面 Summary
?,并生成RPK文件;app.js
?,即:源碼中的?app.ux
?;mocha
?、?assert
?、?expect
?、?should
?測試類庫,與全局函數(shù)?loadData(key)
?、?saveData(key, value)
?;manifest.json
?的定義,加載首頁?Summary
?,呈現(xiàn)匯總頁面的初始狀態(tài),此時還沒有執(zhí)行任何的頁面測試;mocha
?,并完成?test
?目錄下對應(yīng)的測試JS文件的執(zhí)行,并得到測試結(jié)果,最后返回到匯總頁面?Summary
?;Summary
?,此時會展現(xiàn)每個頁面的執(zhí)行結(jié)果;開發(fā)者可以點擊每條記錄,查看正確與出錯的測試詳情;有些開發(fā)者,希望能夠?qū)鞈?yīng)用項目中的源碼在做測試的同時,也能夠看到代碼執(zhí)行的覆蓋率,比如:使用 ?istanbul工具
?;
因此,介紹快應(yīng)用中使用?Istanbul
?的步驟:
--enable-istanbul
?(??hap-toolkit@0.6.13
?開始支持該參數(shù)
?);編譯時會對源碼進行處理,增加Istanbul相關(guān)代碼監(jiān)測(行數(shù)、塊級、分支)的改造,最終生成編譯后的JS文件;
參考示例項目?quickapp-demo-quality
?中?package.json的build:test:istanbul
?命令;
__coverage__
?中;此時,所有頁面的執(zhí)行結(jié)果都會保存下來,變量?__coverage__
?為普通的JS對象,每個屬性代表各頁面的路徑,對應(yīng)的值代表頁面運行結(jié)果;
參考示例項目?quickapp-demo-quality
?中?build
?目錄下生成的各頁面JS代碼,搜索關(guān)鍵字?__coverage__
?;
此時,開發(fā)者在頁面?src/Summary/Index.ux
?中點擊按鈕?保存代碼覆蓋率數(shù)據(jù)
?,事件通過?fetch
?接口,將記錄數(shù)據(jù)發(fā)送到PC上的快應(yīng)用NodeJS服務(wù)器,并以JSON格式保存數(shù)據(jù)在項目根目錄下的?.nyc_output
?文件夾中;
參考示例項目?quickapp-demo-quality
?中?src/Summary/index.ux
?頁面的?saveIstanbulCoverageData()
?方法;
此時,開發(fā)者在根目錄下運行:?nyc report
?,它會讀取根目錄下的配置文件?nyc.config.js
?完成轉(zhuǎn)換,并保存在文件夾?coverage
?中;
參考示例項目?quickapp-demo-quality
?中已經(jīng)安裝的依賴?類庫nyc
?,或者使用?npx nyc report
?也可以達到同樣效果;
coverage
?目錄中的?index.html
?頁面即可查看全部頁面的結(jié)果;下圖展示:記錄的頁面JS文件的表格數(shù)據(jù):
下圖展示:記錄某個頁面JS文件的詳細數(shù)據(jù):
當前快應(yīng)用的測試方式與程序化能力,輔助開發(fā)者完成功能等上的保證,從而確定項目的穩(wěn)定性,提升維護性。
Copyright©2021 w3cschool編程獅|閩ICP備15016281號-3|閩公網(wǎng)安備35020302033924號
違法和不良信息舉報電話:173-0602-2364|舉報郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號
聯(lián)系方式:
更多建議: