Karma:1. 集成 Karma 和 Jasmine 進行單元測試


關於 Karma 會是一個系列,討論在各種環境下,使用 Karma 進行單元測試。

本文討論 karma 集成 Jasmine 進行單元測試。

初始化 NPM

實現初始化 NPM 包管理,創建 package.json 項目管理文件。

使用參數 -y 直接按照默認值創建 packgae.json 項目管理文件。

PS C:\study\mykarma> npm init -y
Wrote to C:\study\mykarma\package.json:

{
  "name": "mykarma",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

 現在,可以在項目文件夾中看到 package.json 文件已經創建了。

安裝 Karma

現在,可以直接使用 NPM 來安裝 karma。

i 是 install 命令的縮寫,-D 是 --save-dev 的縮寫。


PS C:\study\mykarma> npm i -D karma
npm WARN package.json mykarma@1.0.0 No description
npm WARN package.json mykarma@1.0.0 No repository field.
npm WARN package.json mykarma@1.0.0 No README data
npm WARN optional dep failed, continuing fsevents@1.0.7
karma@0.13.21 node_modules\karma
├── batch@0.5.3
├── di@0.0.1
├── graceful-fs@4.1.3
├── rimraf@2.5.2
├── mime@1.3.4
├── colors@1.1.2
├── source-map@0.5.3
├── isbinaryfile@3.0.0
├── bluebird@2.10.2
├── dom-serialize@2.2.1 (custom-event@1.0.0, void-elements@2.0.1, extend@3.0.0, ent@2.2.0)
├── http-proxy@1.13.2 (eventemitter3@1.1.1, requires-port@1.0.0)
├── optimist@0.6.1 (wordwrap@0.0.3, minimist@0.0.10)
├── glob@7.0.0 (path-is-absolute@1.0.0, inherits@2.0.1, once@1.3.3, inflight@1.0.4)
├── useragent@2.1.8 (lru-cache@2.2.4)
├── minimatch@3.0.0 (brace-expansion@1.1.3)
├── lodash@3.10.1
├── expand-braces@0.1.2 (array-unique@0.2.1, array-slice@0.2.3, braces@0.1.5)
├── log4js@0.6.31 (semver@4.3.6, readable-stream@1.0.33)
├── connect@3.4.1 (utils-merge@1.0.0, parseurl@1.3.1, debug@2.2.0, finalhandler@0.4.1)
├── core-js@2.1.0
├── body-parser@1.15.0 (content-type@1.0.1, bytes@2.2.0, depd@1.1.0, raw-body@2.1.5, debug@2.2.0, qs@6.1.0, iconv-lite@0.4.13, http-errors@1.4.0, on-finished@2.3.0, type-is@1.6.11)
├── socket.io@1.4.5 (debug@2.2.0, has-binary@0.1.7, socket.io-parser@2.2.6, socket.io-adapter@0.4.0, engine.io@1.6.8, socket.io-client@1.4.5)
└── chokidar@1.4.2 (path-is-absolute@1.0.0, inherits@2.0.1, async-each@0.1.6, glob-parent@2.0.0, is-binary-path@1.0.1, is-glob@2.0.1, readdirp@2.0.0, anymatch@1.3.0)

PS C:\study\mykarma>

現在我們可以使用 node 來運行 karma  了。

 >node ./node_modules/karma/bin/karma

 

為了能在命令行直接執行 karma 命令,我們再按着一個 karma-cli.

-g 表示全局安裝,這樣可以在系統的任何文件夾中直接執行 karma 命令。

PS C:\study\mykarma> npm i -g karma-cli
C:\Users\XXX\AppData\Roaming\npm\karma -> C:\Users\XXX\AppData\Roaming\npm\node_modules\karma-cli\bin\karma 
karma-cli@0.1.2 C:\Users\guanjun\AppData\Roaming\npm\node_modules\karma-cli
└── resolve@1.1.7

安裝之后,可以直接使用 karma 來啟動測試了,首先檢查一下當前的版本。

PS C:\study\mykarma> karma --version
Karma version: 0.13.21
PS C:\study\mykarma>

 祝賀你, 基本的 Karma 已經安裝成功了。

 

安裝 Jasmine 和 chrome-launcher

我們使用 Karma 來驅動單元測試,所以只有 Karma 是不行的,還需要安裝單元測試庫以便運行測試腳本,安裝測試庫與 Karma 的適配器,還有各種瀏覽器的適配器。

這里我們安裝 Jasmine 的測試支持和 chrome 瀏覽器的適配器。

對於 jasmine 來說,我們需要 Jasmine 的適配器,還必須有 jasmine-core 庫。

karma-chrome-launcher 則提供了 karma 與 chrome 的適配器。

PS C:\study\mykarma> npm i -D jasmine-core karma-jasmine karma-chrome-launcher
npm WARN package.json mykarma@1.0.0 No description
npm WARN package.json mykarma@1.0.0 No repository field.
npm WARN package.json mykarma@1.0.0 No README data
npm WARN peerDependencies The peer dependency jasmine-core@* included from karma-jasmine will no
npm WARN peerDependencies longer be automatically installed to fulfill the peerDependency
npm WARN peerDependencies in npm 3+. Your application will need to depend on it explicitly.
jasmine-core@2.4.1 node_modules\jasmine-core

karma-jasmine@0.3.7 node_modules\karma-jasmine

karma-chrome-launcher@0.2.2 node_modules\karma-chrome-launcher
├── fs-access@1.0.0 (null-check@1.0.0)
└── which@1.2.4 (isexe@1.1.2, is-absolute@0.1.7)

 現在涉及單元測試的基本工具已經安裝就緒了。

  Karma 的命令

karma 支持三個命令。

  • start [<configFile>] [<options>] 啟動 Karma 持續執行,也可以執行單次的測試,然后直接收集測試結果.
  • init [<configFile>] 初始化配置文件.
  • run [<options>] [ -- <clientArgs>] Trigger a test run. 

創建 karma 配置文件

Karma 需要進行配置,配置文件比較復雜,可以使用 karma 提供的 init 命令來直接創建基礎的配置文件。在處理過程中,我們可以使用交互方式提供測試的信息,Karma 根據這些信息生成一個基本的配置文件。配置文件的默認名稱是 karma.conf.js。如果你提供了配置文件的名稱,karma 會將配置信息寫入到你提供的文件名中。

創建 Karma 配置文件

PS C:\study\mykarma> karma init

Which testing framework do you want to use ?
Press tab to list possible options. Enter to move to the next question.
> jasmine


Do you want to use Require.js ?
This will add Require.js plugin.
Press tab to list possible options. Enter to move to the next question.
> no

Do you want to capture any browsers automatically ?
Press tab to list possible options. Enter empty string to move to the next qu
ion.
> Chrome
>

What is the location of your source and test files ?
You can use glob patterns, eg. "js/*.js" or "test/**/*Spec.js".
Enter empty string to move to the next question.
> src/**/*.js
20 02 2016 22:32:26.698:WARN [init]: There is no file matching this pattern.

> test/**/*.spec.js
20 02 2016 22:33:26.513:WARN [init]: There is no file matching this pattern.

>

Should any of the files included by the previous patterns be excluded ?
You can use glob patterns, eg. "**/*.swp".
Enter empty string to move to the next question.
>

Do you want Karma to watch all the files and run the tests on change ?
Press tab to list possible options.
> yes


Config file generated at "C:\study\mykarma\karma.conf.js".

PS C:\study\mykarma>

 由於我們沒有提供配置文件名稱,這里生成的是默認的配置文件 karma.conf.js 。

 啟動 Karma

由於已經有了 karma 配置文件,現在可以使用 karma start 啟動 karma 了,由於還沒有測試,所以看不到測試結果是正常的。

需要注意的是 karma 配置中的 singleRun 這個參數,設置為 false 的話,karma 會自動監控測試環境,默認是 Chrome, 如果你關掉了,karma 會自動重新啟動一個。如果配置為 true,執行一次測試之后,karma 會自動停掉。

在 singleRun 為 false 的情況下,執行的結果可能是這樣的。

PS C:\study\mykarma> karma start
22 02 2016 10:54:11.796:INFO [karma]: Karma v0.13.21 server started at http://localhost:9876/
22 02 2016 10:54:11.806:INFO [launcher]: Starting browser Chrome
22 02 2016 10:54:13.206:INFO [Chrome 47.0.2526 (Windows 7 0.0.0)]: Connected on socket /#rbiYFxG0uTVJxpVoAAAA with id 13601272

 

 

單元測試

成功和失敗

現在我們可以使用 Jasmine 開始寫測試了。

在項目文件夾中,創建一個名為 test 的子文件夾來保存測試用例。然后在 test 文件夾中創建一個 unit 的文件夾來保存單元測試用例。

在這個文件夾中創建一個名為 hello.spec.js 的測試文件。

一般來說,我們會為測試用例的文件名稱提供一個特定的模式,以便對測試用例進行統一處理,這里我們約定測試用例的文件名以 .spec.js 為結尾。

hello.spec.js

describe('hello, unit test.', function(){
  it('should also be able to test', function(){
    expect(true).toBe(true);
  });
  
  it('should be failed', function(){
      expect(true).toBe(false);
  })
});

 

 這個測試包含了兩個測試用例,一個一定成功,一個一定失敗。

確認在我們 karma 的配置文件中,包含了我們的測試用例。

    // list of files / patterns to load in the browser
    files: [
      'test/**/*.spec.js'
    ],

 

現在,使用 karma start 啟動測試,在控制台應該會看到如下的輸出。

PS C:\study\mykarma> karma start
22 02 2016 11:09:31.137:WARN [karma]: No captured browser, open http://localhost:9876/
22 02 2016 11:09:31.157:INFO [karma]: Karma v0.13.21 server started at http://localhost:9876/
22 02 2016 11:09:31.167:INFO [launcher]: Starting browser Chrome
22 02 2016 11:09:32.561:INFO [Chrome 47.0.2526 (Windows 7 0.0.0)]: Connected on socket /#ymfXfb-xI2a3fZ82AAAA with id 31292195
Chrome 47.0.2526 (Windows 7 0.0.0) hello, unit test. should be failed FAILED
        Expected true to be false.
            at Object.<anonymous> (C:/study/mykarma/test/unit/hello.spec.js:7:20)
Chrome 47.0.2526 (Windows 7 0.0.0): Executed 2 of 2 (1 FAILED) (0.016 secs / 0.006 secs)

 

可以看到執行了兩個測試,其中一個失敗了,失敗的測試為 hello, unit test 中的 should be failed 測試用例。

測試實際的代碼

在項目文件夾中,創建一個名為 src 的子文件夾來保存我們的應用代碼,在其中創建一個名為 add.js 的腳本文件,我們將來測試它的工作是否正確。

function add(a, b){
    return a + b;
}

 

這個腳本非常簡單,僅僅用來計算兩個數字之后,沒有任何的驗證。

然后,我們針對它寫兩個測試用例,保存到 ./test/unit/add.spec.js 文件中。

describe('add function unit test.', function(){
    it('2 + 3 = 5', function(){
        var result  = add( 2, 3 );
        expect( result ).toBe( 5 );
    });
  
    it('2 + 3 = 6, this should faild.', function(){
        var result = add( 2, 3 );
        expect(result).toBe( 6 );
    })
});

 

確認你的 karma 配置文件中,包含了被測試代碼和測試代碼。

    // list of files / patterns to load in the browser
    files: [
      'src/**/*.js',
      'test/**/*.spec.js'
    ],

 

現在的控制台輸出應該是這樣的。

PS C:\study\mykarma> karma start
22 02 2016 11:22:18.800:WARN [karma]: No captured browser, open http://localhost:9876/
22 02 2016 11:22:18.810:INFO [karma]: Karma v0.13.21 server started at http://localhost:9876/
22 02 2016 11:22:18.820:INFO [launcher]: Starting browser Chrome
22 02 2016 11:22:20.232:INFO [Chrome 47.0.2526 (Windows 7 0.0.0)]: Connected on socket /#i6GaDaxNTy8HWL52AAAA with id 89457157
Chrome 47.0.2526 (Windows 7 0.0.0) add function unit test. 2 + 3 = 6, this should faild. FAILED
        Expected 5 to be 6.
            at Object.<anonymous> (C:/study/mykarma/test/unit/add.spec.js:9:24)
Chrome 47.0.2526 (Windows 7 0.0.0) hello, unit test. should be failed FAILED
        Expected true to be false.
            at Object.<anonymous> (C:/study/mykarma/test/unit/hello.spec.js:7:20)
Chrome 47.0.2526 (Windows 7 0.0.0): Executed 4 of 4 (2 FAILED) (0.021 secs / 0.007 secs)

 

祝賀你,現在你已經可以測試你的代碼了!

如果你的應用是由一個一個獨立的函數定義出來的,現在就已經可以進行測試了。

Karma 執行原理

在 Karma 啟動的瀏覽器界面中,可以看到當前的執行狀態。

點擊 DEBUG 按鈕,可以進入實際的測試頁面。

這個頁面看起來是空白的,但是執行了實際的測試腳本,進入瀏覽器的開發者模式,可以看到實際的內容。比如,我們上面的實際執行內容。

查看頁面源碼,可以看到這個 Karma 生成的頁面。

<!doctype html>
<!--
This file is almost the same as context.html - loads all source files,
but its purpose is to be loaded in the main frame (not within an iframe),
just for immediate execution, without reporting to Karma server.
-->
<html>
<head>
  <title>Karma DEBUG RUNNER</title>
  <link href="favicon.ico" rel="icon" type="image/x-icon" />
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" />
</head>
<body>
  <!-- The scripts need to be at the end of body, so that some test running frameworks
   (Angular Scenario, for example) need the body to be loaded so that it can insert its magic
   into it. If it is before body, then it fails to find the body and crashes and burns in an epic
   manner. -->
  <script type="text/javascript">
    window.__karma__ = {
      info: function(info) {
        if (info.dump && window.console) window.console.log(info.dump);
      },
      complete: function() {
        if (window.console) window.console.log('Skipped ' + this.skipped + ' tests');
      },
      store: function() {},
      skipped: 0,
      result: window.console ? function(result) {
        if (result.skipped) {
          this.skipped++;
          return;
        }
        var msg = result.success ? 'SUCCESS ' : 'FAILED ';
        window.console.log(msg + result.suite.join(' ') + ' ' + result.description);

        for (var i = 0; i < result.log.length; i++) {
          window.console.error(result.log[i]);
        }
      } : function() {},
      loaded: function() {
        this.start();
      }
    };

    window.__karma__.config = {"args":[],"useIframe":true,"captureConsole":true,"clearContext":true};


    // All served files with the latest timestamps
    window.__karma__.files = {
  '/base/node_modules/jasmine-core/lib/jasmine-core/jasmine.js': '391e45351df9ee35392d2e5cb623221a969fc009',
  '/base/node_modules/karma-jasmine/lib/boot.js': '4a7da64f416169520c9d5c43b5a7feac6bde9104',
  '/base/node_modules/karma-jasmine/lib/adapter.js': 'd76809fbd57147a108ceb7fe2c134b2d39806a9a',
  '/base/src/add.js': 'dd99cc5693226f200581da90d5f231a95e6bb720',
  '/base/test/unit/add.spec.js': 'f430471235f184ab5e13c14ccb87740b833487d6',
  '/base/test/unit/hello.spec.js': '5b7173f9c7e05f6aadc798a5065cd6dc572d005d'
};

  </script>
  <!-- Dynamically replaced with <script> tags -->
<script type="text/javascript" src="/base/node_modules/jasmine-core/lib/jasmine-core/jasmine.js"></script>
<script type="text/javascript" src="/base/node_modules/karma-jasmine/lib/boot.js"></script>
<script type="text/javascript" src="/base/node_modules/karma-jasmine/lib/adapter.js"></script>
<script type="text/javascript" src="/base/src/add.js"></script>
<script type="text/javascript" src="/base/test/unit/add.spec.js"></script>
<script type="text/javascript" src="/base/test/unit/hello.spec.js"></script>
<script type="text/javascript">
    window.__karma__.loaded();
</script>
</body>
</html>

 

關鍵的內容在頁面的后部。

<!-- Dynamically replaced with <script> tags -->
<script type="text/javascript" src="/base/node_modules/jasmine-core/lib/jasmine-core/jasmine.js"></script>
<script type="text/javascript" src="/base/node_modules/karma-jasmine/lib/boot.js"></script>
<script type="text/javascript" src="/base/node_modules/karma-jasmine/lib/adapter.js"></script>
<script type="text/javascript" src="/base/src/add.js"></script>
<script type="text/javascript" src="/base/test/unit/add.spec.js"></script>
<script type="text/javascript" src="/base/test/unit/hello.spec.js"></script>
<script type="text/javascript">
    window.__karma__.loaded();
</script>

 

在這個頁面,我們可以在源碼中設置斷點,檢查測試。

 

總結

可以看到,使用 Karma 集成 Jasmine 測試是很方便的組合。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM