Visual Studio Apache Cordova Apps 單元測試首部曲

這篇文章中您可以閱讀到以下資訊:

要做一個好的 App 就像是偉大的藝術家,演員和運動選手,都是場偉大的演出。人們透過大量的訓練、練習、演練以及實際的回饋檢討,不斷的驗證及持續改善他們的演出。在橫跨整個 App 生命週期裡,我們透過許多層次的嚴格測試,或持續驗證來實現軟體開發上相同的目標。

也許你聽過單元測試,但很可能你並不怎麼清楚明白單元測試實際上是什麼,以及該如何在跨平台的 Apache Cordova 專案上結合單元測試。在 Visual Studio Tools for Apache Cordova 文件內容裡,我們最近新增了一個章節,透過一系列全面性的例子來探討 Cordova apps 的單元測試細節。

在這二篇的文章裡,我會透過一個精簡版本的示範讓大家熟知整個過程。第一篇首先說明單元測試的本質以及一個使用 Visual Studio來進行的基本 Cordova apps 範例,第二篇將稍微深入一點有關測試驅動開發以及單元測試偵錯的主題。

 

單元測試與其它形式的測試

 單元測試相較於其它形式測試的獨特點

單元測試

其它形式

直接呼叫或使用App的程式碼測試單位(類別、方法、屬性及方法)

透過使用者界面測試已部署在模擬器或測試設備上的 App

了解到App的程式碼是怎麼寫的(白箱測試)

無法了解到 App 的程式碼是怎麼寫的(黑箱測試)

測試是執行在開發及建置機器的測試執行器(例如一個獨立的JavaScript 執行環境,Node.js)

測試是在模擬器或實體設備上執行的

測試是自我的一部份程式碼 ( 通常是以相同語言撰寫的,例如JavaScript )

測試是腳本(手動撰寫或由錄製器產生)或者只是一組手動測試的步驟

發生於開發週期裡,同步撰寫程式碼甚至是早於開發階段 ( 測試驅動開發TDD )

發生在開發建置成功後

理想情況下是非常快速的,所以可以結合在每一次的建置過程中,有助於程式碼變更時進行回歸測試

是否有時效性 ( 取決於發行管理的過程 )

測試失敗時中止建置或是提交至版本管理

測試失敗是發行管理的流程中止步驟

下圖說明了多數的測試形式(左側)不同於單元測試 (右側),以及說明了單元測試通常獨立於應用程式平台之外。

 

注釋:當你著手於單元測試是完全專注於撰寫或修改程式碼。你不需測試函式庫或其它不是在專案裡正在修改的程式碼,因為這些函式開發者應該已經測試完它們。如果測試欠缺你所需要使用的函式庫,那麼正確的做法應該是在函式庫的原始碼來源進行,而不是在你的專案裡。

 

JavaScript 與 Apache Cordova 的單元測試環境

單元測試環境由三個組成項目:執行階段 (runtime),測試框架 (Test framework) 和測試執行器  (test runner)。以下列表說明了這些項目,並且有一些例子。

項目

說明

JavaScript例子

執行階段(runtime)

在App之外裝載並執行程式碼。它可以一個瀏覽器或是獨立的執行環境,有時被稱做為headless browser

Browsers, or Node.js, PhantomJS, Chrome V8

測試框架(Test framework)

定義如何撰寫具體的”測試”,通常是在同樣的程式語言裡被測試,這樣可以共享相同的執行階段(runtime),但這不是必需的。

Jasmine, QUnit, Mocha along with libraries like Chai and assert.js

測試執行器(test runner)

在所支援的執行階段(runtime)裡執行依測試框(Test framework)架定義的測試,並且產出測試報告。

Chutzpah (uses PhantomJS), Karma (uses a browser)

這些關係如下圖所示:

 

單元測試是在適當的時間點調用測試執行器 (test runner) 和查看報告,它可以透過手動進行或是在自動建置過程中的一部份,測試執行器 (test runner) 可以利用命令模式或是整合於 Visual Studio IDE。

一些測試執行器 (test runner),例如 Chutzpah,有整合 Visual Studio 測試橋接器工具,反應在 Visual Studio 測試總管介面裡。其它測試執行器 (test runner),例如 Karma,沒有測試橋接器但它仍然可以整合到 Visual Studio 的工作執行器總管 (Task Runner Explorer),關連到像是 Grunt 及 gulp 。這二種方式都含蓋在文件裡,針對 Karma 及 gulp,請查閱 Basic unit testing  及 Test Apache Cordova apps with Karma and Jasmine

 

動手做單元測試

為了更好理解單元測試的機制,讓我們現在用一段程式碼,透過 Chutzpah,QUnit (jQuery的 unit test framework),以及 Visual Studio 來進行基本的單元測試過程。

 

unit”

首先,假設你已經安裝了 Visual Studio Tools for Apache Cordova,然後透過"檔案 > 新增 > 專案 > 選擇 JavaScript >Apache Cordova Apps > 空白應用程式"。然後在 www/scripts 資料夾建立一個叫做 normalize.js 的 JavaScript 檔案,並且輸入以下的程式碼。 

 /** @description Converts JSON data that may contain Name and PersonalIdentifier 
 *    properties to an object with the properties name (string) and id (positive 
 *    integer up to 9999999999.
 * @param {string} jsonIn The JSON data to normalize.
 * @return {object} An object with name (string) and id (integer) properties,
 *    defaulting to "default" and 0, or null if the JSON is null or invalid.
 */
function normalizeData(jsonIn) {
}

 這個簡單的 normalizeData 函式是我們要測試的單元 (unit),現在我們先讓它保持空白。請注意到這個函式是 App 的一個函式,它跟我們所選擇的測試框架 (test framework) 及測試執行器 (test runner) 無關。

 

單元測試

接下來,每個單元測試都是一段驗證單元的程式碼,透過:

  1. 給與特定的輸入值然後呼叫,接著
  2. 確認期望值的輸出

單元測試必須遵循你所使用的測試框架 (test framework)。因為我們正在測試 JavaScript 程式碼,我們有眾多容易使用的 JavaScript  測試框架可以選擇。在這個例子中,我們將要使用 Jasmine ,它內建支援我們待會要使用的 Chutzpah 測試執行器 (test runner),所以我們不需要額外為 Jasmine 安裝其它特別的東西。

針對單元測試,在專案內建立一個資料夾並命名為 Test,然後在這個資料夾內建立一個 normalize_tests.js 的 JavaScript 檔案,並且輸入以下內容:

 // First argument to "describe" is the name of this group of tests
describe("normalizeData tests", function () {
    // First argument to "it" is the name of the specific test
    it("accepts golden path data", function () {
        // Use the unit being tested as necessary
        var json = '{"Name": "Maria", "PersonalIdentifier": 2111858}';
        var norm = normalizeData(json);

        // Check the results; "expect" is a Jasmine method.
        expect(norm.name).toEqual("Maria");
        expect(norm.id).toEqual(2111858);
    });
});

在 Jasmine 裡,你建立了一組測試在 describe 方法裡,然後每一個測試在it函式裡,最後形成描繪出這個整個測試。使用單元測試程式碼針對任何你想要的測試,然後使用 Jasmine 的 expect 方法確認結果,最終輸出 pass 或 fail 。

這裡我們只是一個簡單的測試,但請注意它是很明確具體,有特定的輸入呼叫,並且針對輸入給定了確切的名稱/描述。這遵循了最佳原則,每個測試針對一個測試案例,測試的名稱建立成 1:1 的對應,因為這個名稱會呈現在報告上,以及精確的測試案例(意謂:測試使用的參數)。當測試執行器 (test runner) 報告失敗時,你可以確切的知道到哪裡查看你的程式碼,然後很輕易透過在除錯器的測試到達失敗點。這最終會節省你的時間,因為假如你合併多個的測試,當你必須偵錯哪裡失敗時,你很有可能最後會解析所有測試。

 

 測試執行器 (test runner)

有了單元程式碼以及至少一個單元測試,現在我們可以執行 Chutzpah 測試執行器 (test runner)。先到 Visual Studio 裡的"工具>擴充功能和更新….",選擇線上,搜尋及安裝"Chutzpah Test Adapter"(你會被提示重新啟動 Visual Studio)

 

在專案根目錄下建立 Chutzpah.json 檔案,然後輸入以下內容,告訴 Chutzpah 它應該執行的檔案。

 {
  "References": [
    { "Path": "www/scripts/js/normalize.js" }
  ],

  "Tests": [
      { "Path": "test/normalize_tests.js" }
  ]
}

“References” 區段用來明確指定要測試的程式碼,然後“Tests”區段指定單元測試檔案。當你加入愈多程式碼及測試檔案時,這個列表清單就會愈多。

現在選擇"測試 > 視窗 > 測試總管"然後你應該會看到列出可用的測試清單 “References”  區段用來明確指定要測試的程式碼,然後 “Tests” 區段指定單元測試檔案。當你加入愈多程式碼及測試檔案時,這個列表清單就會愈多。

 

注意:如果沒有任何清單,那很有可能是你的測試檔案有語法上的錯誤,而造成 Chutzpah 無法辨示。

點選全部執行,開始建置專案,執行測試,並查看結果。因為我們在 normalizeData 裡沒有任何實作,所以測試應該會失敗:

這證實了你具有可以在 Visual Studio 裡使用 Chutzpah 的機制。

如果你想要通過測試,實作 normalizeData,至少處理預期的輸入,然後再次執行測試:

 function normalizeData(jsonIn) {
    data = JSON.parse(jsonIn);
    return {
        name: data.Name,
        id: Number(data.PersonalIdentifier)
    };
}

當然這個程式碼無法完美的處理其它 JSON,所以肯定是有改善的空間!我們將會在第二篇來談論有關於測試驅動開發 (test-driven development) 以及單元測試除錯。

在此同時,我希望聽聽你是如何在 Cordova apps 進行單元測試,你是如何進行 UI 測試(手動及自動),以及我們可以如何進一步提升我們的支援透過 Visual Studio Tools for Apache Cordova。透過 kraigb (at) microsoft.com留言給我,或是到 https://visualstudio.uservoice.com/. 提出建議。當然這個程式碼無法完美的處理其它 JSON,所以肯定是有改善的空間!我們將會在第二篇來談論有關於測試驅動開發 (test-driven development) 以及單元測試除錯。

本文翻譯自 Unit Testing Apache Cordova Apps with Visual Studio, Part 1

[延伸閱讀 - 影片教學]  

使用 Visual Studio 2015 TACO 建置 Windows 10 應用程式

Visual Studio 2015 tools for Apache Cordova Build apps for Windows 10