快應(yīng)用 自動化測試

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

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

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

傳統(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?等工具完成斷言;

  • e2e測試

主要針對項目與頁面級別的測試,確保項目的基本功能暢通,是對項目上線的一個主要保障;

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

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

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

功能覆蓋的角度

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

  • 接口測試

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

  • 界面測試

主要針對頁面局部的UI布局渲染正確,確定:文本、對話框、滑動等節(jié)點存在,位置正確;

  • 功能測試

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

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

在快應(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?);

1. 新建示例項目

使用命令行新建一個自定義項目,名稱為:?quickapp-demo-quality?

  npx hap init quickapp-demo-quality

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

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

2. 添加并編寫測試用例

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

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

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

testing-1

其中針對?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()
    })
  })
}

3. 生成要測試的頁面

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

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


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

export {
  autoCaseList
}

該文件供下面的測試匯總頁面使用,聲明哪些頁面需要進行?e2e?測試。

4. 增加測試匯總頁面與自動化能力

上一步僅代表哪些頁面需要進行測試,并測試頁面中的哪些能力;

這一步主要完成兩件事:

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

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

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

掃碼打開頁面并點擊按鈕?點擊重新測試?,完成一整套自動化測試過程。

最終的示例效果如下:

testing-41

方案實現(xiàn)原理

上面這種e2e的測試方式,并不需要修改框架運行時,即:不需要前端框架配合修改某些代碼;

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

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

編譯時

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

運行時

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

代碼覆蓋率

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

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

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

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

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

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

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

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

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

此時,開發(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()?方法;

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

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

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

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

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

istanbul-result1

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

istanbul-result2

其它參考

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

總結(jié)

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


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

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號