99re热这里只有精品视频,7777色鬼xxxx欧美色妇,国产成人精品一区二三区在线观看,内射爽无广熟女亚洲,精品人妻av一区二区三区

快應(yīng)用 自動(dòng)化測(cè)試

2020-08-10 11:18 更新
測(cè)試是軟件開發(fā)中必不可少的一個(gè)環(huán)節(jié),程序化測(cè)試能夠加快研發(fā)速度,提高協(xié)作效率,減少產(chǎn)品故障。

通過本節(jié),你將學(xué)會(huì):

傳統(tǒng)測(cè)試的分類

傳統(tǒng)前端項(xiàng)目的測(cè)試,可以從兩個(gè)維度去做分類:

粗細(xì)粒度的角度

從粗細(xì)粒度的角度看,測(cè)試分為以下幾類:

  • 單元測(cè)試

主要針對(duì)JS中的某些方法(不包括ux中的定義),這些方法獨(dú)立性強(qiáng),不強(qiáng)依賴于外部環(huán)境;

這類需求有明確的輸入輸出要求,通過常規(guī)的測(cè)試框架即可完成,如:mocha、Jest;

  • 集成測(cè)試

主要針對(duì)功能比較完整的模塊或者組件,它們是多個(gè)單元/模塊的組裝與業(yè)務(wù)結(jié)合;

這類需求希望面對(duì)常見的業(yè)務(wù)應(yīng)用場(chǎng)景,能夠得到正確的界面渲染與數(shù)據(jù)結(jié)構(gòu);

在當(dāng)前的快應(yīng)用平臺(tái)中,如果用到自定義組件或者底層接口(如:@system.fetch),需要依賴于真機(jī)環(huán)境進(jìn)行測(cè)試確認(rèn)結(jié)果;

當(dāng)然,部分開發(fā)者希望能夠提供一個(gè)模擬環(huán)境(如:NodeJS)的快應(yīng)用平臺(tái),方便在PC上完成測(cè)試,目前這個(gè)能力僅團(tuán)隊(duì)內(nèi)部使用,考慮到更新頻次較高,暫沒有對(duì)外開放;

實(shí)際上,優(yōu)先推薦開發(fā)者使用真機(jī)環(huán)境通過自動(dòng)化的方式完成確認(rèn),這樣可以確保多手機(jī)廠商設(shè)備下對(duì)功能的統(tǒng)一能力確認(rèn);

針對(duì)這類測(cè)試的實(shí)現(xiàn),開發(fā)者可以考慮在快應(yīng)用項(xiàng)目中建立新的能力測(cè)試頁(yè)面,引入待測(cè)試的自定義組件與模塊,通過?mocha?、?Jest?等工具完成斷言;

  • e2e測(cè)試

主要針對(duì)項(xiàng)目與頁(yè)面級(jí)別的測(cè)試,確保項(xiàng)目的基本功能暢通,是對(duì)項(xiàng)目上線的一個(gè)主要保障;

這類需求的原理就是通過真實(shí)的瀏覽器去運(yùn)行每個(gè)頁(yè)面,模擬用戶行為操作,確保界面的一致性,功能正確;

對(duì)于WEB的前端開發(fā)者通過?Karma?、?Selenium?等工具,完成對(duì)瀏覽器操作的自動(dòng)化封裝,最終測(cè)試頁(yè)面與后端服務(wù)器的正確配合;

對(duì)于快應(yīng)用的前端開發(fā)者,需要借助于一些接口與簡(jiǎn)單類庫(kù)封裝,來承載頁(yè)面的加載、切換等測(cè)試任務(wù);

功能覆蓋的角度

從功能覆蓋的角度,測(cè)試可以分為幾類:

  • 接口測(cè)試

主要針對(duì)底層為前端開發(fā)者提供的接口,確保這些接口在跨設(shè)備上行為和輸出正確;如:?@system.storage?;

  • 界面測(cè)試

主要針對(duì)頁(yè)面局部的UI布局渲染正確,確定:文本、對(duì)話框、滑動(dòng)等節(jié)點(diǎn)存在,位置正確;

  • 功能測(cè)試

主要針對(duì)某些行為操作下的功能表現(xiàn)正確,或者小到一個(gè)模塊、一個(gè)方法的輸出正確;

如何測(cè)試快應(yīng)用

在快應(yīng)用的項(xiàng)目中,如果開發(fā)者僅僅只是JS文件中方法的單元測(cè)試的話(不需要引入底層接口),完全可以通過自己引入?mocha?等工具,然后運(yùn)行在PC的NodeJS環(huán)境來實(shí)現(xiàn),這塊實(shí)現(xiàn)簡(jiǎn)單,本文不贅述;

當(dāng)前快應(yīng)用的實(shí)現(xiàn)中,框架為開發(fā)者提供了一套e2e的測(cè)試框架,這類測(cè)試需要運(yùn)行在真實(shí)的手機(jī)設(shè)備中,然后配合?@system.router?接口完成頁(yè)面之間的切換與內(nèi)容測(cè)試,后面介紹原理;

開發(fā)者可以通過以下步驟來為項(xiàng)目引入e2e的測(cè)試能力(當(dāng)前使用的?hap-toolkit?工具版本為:?0.6.8?);

1. 新建示例項(xiàng)目

使用命令行新建一個(gè)自定義項(xiàng)目,名稱為:?quickapp-demo-quality?

  npx hap init quickapp-demo-quality

當(dāng)前,開發(fā)者也可以使用自己已有的項(xiàng)目,用于增加測(cè)試能力;

提示:為了方便開發(fā)者理解并使用,快應(yīng)用官方的 Github站點(diǎn) 提供了 示例項(xiàng)目 ;

2. 添加并編寫測(cè)試用例

在項(xiàng)目中,創(chuàng)建?test?目錄,與?src?目錄同級(jí),該文件夾用于存放所有的頁(yè)面測(cè)試用例;

其中針對(duì)每個(gè)頁(yè)面的測(cè)試用例的文件路徑需要與?src?目錄中對(duì)應(yīng)頁(yè)面的路徑保持一致;

當(dāng)前項(xiàng)目我們添加?Demo?、?DemoDetail?、?About?三個(gè)頁(yè)面的測(cè)試用例。結(jié)構(gòu)如下:

testing-1

其中針對(duì)?Demo?頁(yè)面的測(cè)試用例,舉例如下,其它測(cè)試用例的文件內(nèi)容類似:

/**
* @param vm 代表頁(yè)面的ViewModel實(shí)例
*/
export default function(vm) {
  // 其中describe, it, expect函數(shù)來自于對(duì) mocha, chai的引入;
  describe(`Demo`, function() {
    it(`測(cè)試Detail頁(yè)面vm屬性`, function(done) {
      expect(2).to.equal(3)
      done()
    })

    it(`測(cè)試Detail頁(yè)面vm方法`, function(done) {
      done()
    })
  })
}

3. 生成要測(cè)試的頁(yè)面

在?test?目錄下創(chuàng)建一個(gè)JS文件?autocase.js?,表示所有要測(cè)試的頁(yè)面文件列表,其內(nèi)容如下:

代碼中描述了本次要測(cè)試的頁(yè)面為:?Demo?、?DemoDetail?、?About?;


const autoCaseList = [
  'Demo',
  'DemoDetail',
  'About'
]

export {
  autoCaseList
}

該文件供下面的測(cè)試匯總頁(yè)面使用,聲明哪些頁(yè)面需要進(jìn)行?e2e?測(cè)試。

4. 增加測(cè)試匯總頁(yè)面與自動(dòng)化能力

上一步僅代表哪些頁(yè)面需要進(jìn)行測(cè)試,并測(cè)試頁(yè)面中的哪些能力;

這一步主要完成兩件事:

1) 增加測(cè)試匯總頁(yè)面,記錄測(cè)試結(jié)果;

2) 將各測(cè)試頁(yè)面的結(jié)果與切換連接起來,形成自動(dòng)化;

在?src?目錄下創(chuàng)建一個(gè)測(cè)試匯總的頁(yè)面?Summary?并在?manifest.json?中聲明路由;

頁(yè)面內(nèi)容中的JS代碼部分舉例如下:

<script>
  import router from '@system.router'

  import {
    autoCaseList
  } from '../../test/autocase'

  /**
   * 獲取下一個(gè)自動(dòng)測(cè)試的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: {
      // 包含自動(dòng)測(cè)試腳本的case列表
      pageNameList: [],
      pageTestList: [],
      shouldTestAll: false,
      showCompletedText: false,
      isRunningTest: false
    },
    onInit() {
      this.pageNameList = autoCaseList
      // 初始化自動(dòng)化測(cè)試相關(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()
    },
    /**
     * 重啟整個(gè)所有測(cè)試
     */
    restartTestProcess() {
      // 防止連續(xù)多次點(diǎn)擊
      if (!this.isRunningTest) {
        this.isRunningTest = true
        global.saveData('pageNameList', this.pageNameList)
        global.saveData('pageTestList', [])

        // 重置測(cè)試結(jié)束文本的顯示狀態(tài)
        this.showCompletedText = false
        // 自動(dòng)跑測(cè)試下一個(gè)測(cè)試用例
        this.shouldTestAll = true
        // 啟動(dòng)下個(gè)測(cè)試用例
        this.startNextTestPage()
      }
    },
    /**
     * 啟動(dòng)下個(gè)測(cè)試用例
     */
    async startNextTestPage() {
      const pageItem = findNextTestPage()
      console.info(`下個(gè)測(cè)試用例:${pageItem}`)
      if (pageItem) {
        await waitForOK(1000)
        console.info(`開始測(cè)試頁(yè)面:${pageItem}`)
        router.push({
          uri: pageItem
        })
      } else {
        this.isRunningTest = false
        console.info(`測(cè)試用例列表執(zhí)行完畢`)
        this.showCompletedText = true
        this.shouldTestAll = false
      }
    },
    gotoPage(path, params) {
      // 單個(gè)頁(yè)面的點(diǎn)擊跳轉(zhuǎn):不會(huì)在測(cè)試后,自動(dòng)返回
      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ā)者可以在 官方站點(diǎn)的示例項(xiàng)目 中查看 該頁(yè)面全部?jī)?nèi)容 ,路徑為:src/Summary/index.ux

5. 構(gòu)建自動(dòng)化測(cè)試的RPK文件

在項(xiàng)目目錄下,執(zhí)行構(gòu)建命令 ?npm run build:test?,并運(yùn)行在快應(yīng)用平臺(tái),即可完成自動(dòng)化測(cè)試;

掃碼打開頁(yè)面并點(diǎn)擊按鈕?點(diǎn)擊重新測(cè)試?,完成一整套自動(dòng)化測(cè)試過程。

最終的示例效果如下:

testing-41

方案實(shí)現(xiàn)原理

上面這種e2e的測(cè)試方式,并不需要修改框架運(yùn)行時(shí),即:不需要前端框架配合修改某些代碼;

相反,它的實(shí)現(xiàn)主要是通過:上面的開發(fā)者代碼與?hap-toolkit?編譯時(shí)工具在啟用參數(shù)?--enable-e2e?構(gòu)建后注入的代碼配合完成的;

下面從編譯時(shí)、運(yùn)行時(shí)兩個(gè)方面,介紹實(shí)現(xiàn)原理,方便開發(fā)者理解,并進(jìn)行更深程度的定制與改造;

編譯時(shí)

  1. 開發(fā)者執(zhí)行構(gòu)建命令?npm run build:test?,將會(huì)啟用參數(shù)?--enable-e2e?來創(chuàng)建RPK文件;開發(fā)者可以通過?package.json?查看細(xì)節(jié);
  2. 該參數(shù)啟用后,?hap-toolkit?將會(huì)完成以下幾件事,其中前兩步可以通過?build/app.js?文件查看細(xì)節(jié),后兩部通過?build?目錄下對(duì)應(yīng)的頁(yè)面JS查看細(xì)節(jié);
  3. 向項(xiàng)目的?app.ux?中,注入測(cè)試相關(guān)類庫(kù):?hybrid-mocha?、?hybrid-chai?,他們分別是對(duì)類庫(kù)?mochajs?、?chaijs?的簡(jiǎn)單適配的封裝;
  4. 向項(xiàng)目的?app.ux?中,注入一些全局函數(shù):?loadData(key)?、?saveData(key, value)?提供給每個(gè)頁(yè)面調(diào)用,這兩個(gè)函數(shù)分別用于向JS內(nèi)存中全局獲取數(shù)據(jù)與保存數(shù)據(jù);
  5. 向項(xiàng)目的頁(yè)面級(jí)ux文件中,關(guān)聯(lián)引入?test?目錄中對(duì)應(yīng)的測(cè)試用例文件(相對(duì)路徑保持一致的JS文件);
  6. 向項(xiàng)目的頁(yè)面級(jí)ux文件中,注入?mocha?實(shí)例化與運(yùn)行的代碼,偽代碼如:?const mocha = new Mocha(); mocha.run();?;
  7. ?hap-toolkit?走正常流程,編譯每個(gè)頁(yè)面,如:?匯總頁(yè)面 Summary?,并生成RPK文件;

運(yùn)行時(shí)

  1. 快應(yīng)用啟動(dòng)時(shí),先加載RPK中的?app.js?,即:源碼中的?app.ux?;
  2. 上一步接著會(huì)向全局環(huán)境注入?mocha?、?assert?、?expect?、?should?測(cè)試類庫(kù),與全局函數(shù)?loadData(key)?、?saveData(key, value)?;
  3. 接著根據(jù)?manifest.json?的定義,加載首頁(yè)?Summary?,呈現(xiàn)匯總頁(yè)面的初始狀態(tài),此時(shí)還沒有執(zhí)行任何的頁(yè)面測(cè)試;
  4. 開發(fā)者點(diǎn)擊頁(yè)面中的按鈕點(diǎn)擊重新測(cè)試,就會(huì)執(zhí)行對(duì)應(yīng)的方法restartTestProcess(),該方法將會(huì)依次加載變量autoCaseList中每個(gè)頁(yè)面,直到測(cè)試完成;
  5. 在擁有測(cè)試用例的每個(gè)頁(yè)面中,會(huì)依次實(shí)例化?mocha?,并完成?test?目錄下對(duì)應(yīng)的測(cè)試JS文件的執(zhí)行,并得到測(cè)試結(jié)果,最后返回到匯總頁(yè)面?Summary?;
  6. 所有頁(yè)面測(cè)試完成之后,返回到匯總頁(yè)面?Summary?,此時(shí)會(huì)展現(xiàn)每個(gè)頁(yè)面的執(zhí)行結(jié)果;開發(fā)者可以點(diǎn)擊每條記錄,查看正確與出錯(cuò)的測(cè)試詳情;

代碼覆蓋率

有些開發(fā)者,希望能夠?qū)鞈?yīng)用項(xiàng)目中的源碼在做測(cè)試的同時(shí),也能夠看到代碼執(zhí)行的覆蓋率,比如:使用 ?istanbul工具?;

因此,介紹快應(yīng)用中使用?Istanbul?的步驟:

1. 編譯時(shí)攜帶參數(shù):?--enable-istanbul?(??hap-toolkit@0.6.13?開始支持該參數(shù)?);

編譯時(shí)會(huì)對(duì)源碼進(jìn)行處理,增加Istanbul相關(guān)代碼監(jiān)測(cè)(行數(shù)、塊級(jí)、分支)的改造,最終生成編譯后的JS文件;

參考示例項(xiàng)目?quickapp-demo-quality?中?package.json的build:test:istanbul?命令;

2. 運(yùn)行快應(yīng)用中的各個(gè)頁(yè)面,并將結(jié)果記錄在全局變量?__coverage__?中;

此時(shí),所有頁(yè)面的執(zhí)行結(jié)果都會(huì)保存下來,變量?__coverage__?為普通的JS對(duì)象,每個(gè)屬性代表各頁(yè)面的路徑,對(duì)應(yīng)的值代表頁(yè)面運(yùn)行結(jié)果;

參考示例項(xiàng)目?quickapp-demo-quality?中?build?目錄下生成的各頁(yè)面JS代碼,搜索關(guān)鍵字?__coverage__?;

3. 快應(yīng)用頁(yè)面中保存運(yùn)行結(jié)果;

此時(shí),開發(fā)者在頁(yè)面?src/Summary/Index.ux?中點(diǎn)擊按鈕?保存代碼覆蓋率數(shù)據(jù)?,事件通過?fetch?接口,將記錄數(shù)據(jù)發(fā)送到PC上的快應(yīng)用NodeJS服務(wù)器,并以JSON格式保存數(shù)據(jù)在項(xiàng)目根目錄下的?.nyc_output?文件夾中;

參考示例項(xiàng)目?quickapp-demo-quality?中?src/Summary/index.ux?頁(yè)面的?saveIstanbulCoverageData()?方法;

4. 轉(zhuǎn)換上一步的JSON記錄數(shù)據(jù)為易讀的各類report格式;

此時(shí),開發(fā)者在根目錄下運(yùn)行:?nyc report?,它會(huì)讀取根目錄下的配置文件?nyc.config.js?完成轉(zhuǎn)換,并保存在文件夾?coverage?中;

參考示例項(xiàng)目?quickapp-demo-quality?中已經(jīng)安裝的依賴?類庫(kù)nyc?,或者使用?npx nyc report?也可以達(dá)到同樣效果;

5. 瀏覽器打開?coverage?目錄中的?index.html?頁(yè)面即可查看全部頁(yè)面的結(jié)果;

下圖展示:記錄的頁(yè)面JS文件的表格數(shù)據(jù):

istanbul-result1

下圖展示:記錄某個(gè)頁(yè)面JS文件的詳細(xì)數(shù)據(jù):

istanbul-result2

其它參考

  • Github測(cè)試示例項(xiàng)目:quickapp-demo-quality
  • mochajs官網(wǎng)
  • chaijs官網(wǎng)
  • 探索istanbul/nyc代碼覆蓋工具的原理

總結(jié)

當(dāng)前快應(yīng)用的測(cè)試方式與程序化能力,輔助開發(fā)者完成功能等上的保證,從而確定項(xiàng)目的穩(wěn)定性,提升維護(hù)性。


以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)