JavaScript 單元測試框架:Jasmine 初探

簡介

隨着互聯網浪潮的逐漸興起,各類基於互聯網的雲戰略也不斷涌現,各個公司對雲平臺的理解和實現不盡相同,而云+端的模式愈來愈多受到關注。其中的端能夠理解爲終端用戶手中的各類終端,包括 PC、手機、平板等不一而足。 而愈來愈多的用戶願意在本身的設備上使用輕量級的基於瀏覽器的應用。這類應用的安裝部署能夠是經過插件的方式安裝,也有多是直接以網頁的形式訪問而無需安裝,相對於富客戶端的下載安裝,對用戶來講更加簡單方便,用戶體驗也更好。javascript

這類應用對開發人員來講,須要一些互聯網相關的技術,其中必不可少 HTML CSS 和 JavaScript 技術。而 JavaScript 做爲一種客戶端腳本語言,和傳統編程語言 Cpp、Java 等相比,沒有諸如 Eclipse、Visual Studio 等集成開發調試環境,其調試和測試是對開發人員都是一項挑戰。css

目前 JS 單元測試框架有豐富的選擇,好比 Buster.js、TestSwarm、JsTestDriver 等。而 Jasmine 做爲流行的 JavaScript 測試工具,很輕巧只有 20K 左右,而功能豐富,讓咱們能夠容易的寫出清晰簡潔的針對項目的測試用例。對基於 JavaScript 開發的項目來講,是一款不錯的測試框架選擇。html



搭建環境

獲取安裝包

能夠在開源社區網站下載最新的 Jasmine 安裝包, 目前的 Standalone 的最新版本是 1.3.0. 下載地址: https://github.com/pivotal/jasmine/downloadsjava

配置安裝

下載後的.zip 文件包解壓縮,以下的目錄結構:git

圖 0.目錄結構

目錄結構

其中 lib 文件夾中包含 Jasmine 的源代碼。採用以下相對路徑能夠包含 Jasmine,進而開發基於 Jasmine 的測試用例。github

  <link rel="shortcut icon" type="image/png" href="lib/jasmine-1.3.0/jasmine_favicon.png">
  <link rel="stylesheet" type="text/css" href="lib/jasmine-1.3.0/jasmine.css">
  <script type="text/javascript" src="lib/jasmine-1.3.0/jasmine.js"></script>
  <script type="text/javascript" src="lib/jasmine-1.3.0/jasmine-html.js"></script>

spec 和 src 和 SpecRunner.html 是 Jasmine 的一個完整示例,用瀏覽器打開 SpecRunner.html,便可看到執行的結果。web



基本概念

describe

describe 是 Jasmine 的全局函數,做爲一個 Test Suite 的開始,它一般有 2 個參數:字符串和方法。字符串做爲特定 Suite 的名字和標題。方法是包含實現 Suite 的代碼。編程

清單 1.測試用例
describe("This is an exmaple suite", function() {
  it("contains spec with an expectation", function() {
    expect(true).toBe(true);
    expect(false).toBe(false);
    expect(false).not.toBe(true);
  });
});

Specs

Specs 經過調用 it 的全局函數來定義。和 describe 相似,it 也是有 2 個參數,字符串和方法。每一個 Spec 包含一個或多個 expectations 來測試須要測試代碼。瀏覽器

Jasmine 中的每一個 expectation 是一個斷言,能夠是 true 或者 false。當每一個 Spec 中的全部 expectations 都是 true,則經過測試。有任何一個 expectation 是 false,則未經過測試。而方法的內容就是測試主體。框架

JavaScript 的做用域的規則適用,因此在 describe 定義的變量對 Suite 中的任何 it 代碼塊都是可見的。

清單 2.測試用例
describe("Test suite is a function.", function() {
  var gVar;

  it("Spec is a function.", function() {
    gVar = true;
    expect(gVar).toBe(true);
  });

  it("Another spec is a function.", function() {
    gVar = false;
    expect(gVar).toBe(false);
  });

});

Expectations

Expectations 是由方法 expect 來定義,一個值表明實際值。另外的匹配的方法,表明指望值。

清單 3.測試用例
describe("This is an exmaple suite", function() {
  it("contains spec with an expectation", function() {
    var num = 10;
    expect(num).toEqual(10);
  });
});

以上代碼能夠在附件中的 List.html 運行,結果見下圖:

圖 1.測試用例結果

測試用例結果

總結

describe 方法用來組織相關的 Spec 集合。string 參數做爲 Spec 集合的名字,會和其中的 Spec 鏈接組成 Spec 的完整名字。這樣在一個大的 suite 中能夠更容易找到某個 Spec。若是給它們命名適當,Specs 讀起來是一個典型的 BDD 樣式的句子。

Spec 是做爲測試主體,Suite 是一個或多個 Spec 的集合。

describe 和 it 代碼塊中都是方法,能夠包含任何可執行的代碼來實現測試。而方法的內容就是 Suites。



常見用法

Matchers

每一個 Matchers 實現一個布爾值,在實際值和指望值之間比較。它負責通知 Jasmine,此 expectation 是真或者假。而後 Jasmine 會認爲相應的 spec 是經過仍是失敗。

任何 Matcher 能夠在調用此 Matcher 以前用 not 的 expect 調用,計算負值的判斷。

清單 4.測試用例
describe("The 'toBe' matcher compares with ===", function() {
  it("and has a positive case ", function() {
    expect(true).toBe(true);
  });
  it("and can have a negative case", function() {
    expect(false).not.toBe(true);
  });
});

Included Matchers

Jasmine 有不少的 Matchers 集合。下面的例子中舉例說明一些經常使用的 Matchers。另外當項目須要特定的判斷,而沒有包含在 Jasmine 的 Matchers 時,也能夠經過寫定製的 Matchers 來實現.

清單 5.測試用例
describe("Included matchers:", function() {

  it("The 'toBe' Matcher", function() {
    var a = 3.6;
    var b = a;

    expect(a).toBe(b);
    expect(a).not.toBe(null);
  });

  describe("The 'toEqual' matcher", function() {

    it("works for simple literals and variables", function() {
      var a = "varA";
      expect(a).toEqual("varA");
    });

    it("Work for objects", function() {
      var obj = {
        a: 1,
        b: 4
      };
      var obj2 = {
        a: 1,
        b: 4
      };
      expect(obj).toEqual(obj2);
    });
  });

  it("The 'toBeDefined' matcher ", function() {
    var obj = {
      defined: 'defined'
    };

    expect(obj.defined).toBeDefined();
    expect(obj.undefined).not.toBeDefined();
  });

});

其餘的 Matchers 還有:

toBe()
toNotBe()
toBeDefined()
toBeUndefined()
toBeNull()
toBeTruthy()
toBeFalsy()
toBeLessThan()
toBeGreaterThan()
toEqual()
toNotEqual()
toContain()
toBeCloseTo()
toHaveBeenCalled()
toHaveBeenCalledWith()
toMatch()
toNotMatch()
toThrow()

Setup and Teardown

爲了使某個測試用例乾淨的重複 setup 和 teardown 代碼, Jasmine 提供了全局的 beforeEach 和 afterEach 方法。正像其名字同樣,beforeEach 方法在 describe 中的

每一個 Spec 執行以前運行,afterEach 在每一個 Spec 調用後運行。

這裏的在同一 Spec 集合中的例子有些不一樣。測試中的變量被定義爲全局的 describe 代碼塊中,用來初始化的代碼被挪到 beforeEach 方法中。afterEach 方法在繼續前重置這些變量。

清單 6.測試用例
describe("An example of setup and teardown)", function() {
  var gVar;

  beforeEach(function() {
    gVar = 3.6;
    gVar += 1;
  });

  afterEach(function() {
    gVar = 0;
  });

  it("after setup, gVar has new value.", function() {
    expect(gVar).toEqual(4.6);
  });

  it("A spec contains 2 expectations.", function() {
    gVar = 0;
    expect(gVar).toEqual(0);
    expect(true).toEqual(true);
  });
});

嵌套代碼塊

describe 能夠嵌套, Specs 能夠定義在任何一層。這樣就可讓一個 suite 由一組樹狀的方法組成。在每一個 spec 執行前,Jasmine 遍歷樹結構,按順序執行每一個 beforeEach 方法。Spec 執行後,Jasmine 一樣執行相應的 afterEach。

清單 7.測試用例
describe("A spec", function() {
  var gVar;

  beforeEach(function() {
    gVar = 3.6;
    gVar += 1;
  });

  afterEach(function() {
    gVar = 0;
  });

  it("after setup, gVar has new value.", function() {
    expect(gVar).toEqual(4.6);
  });

  it("A spec contains 2 expectations.", function() {
    gVar = 0;
    expect(gVar).toEqual(0);
    expect(true).toEqual(true);
  });

  describe("nested describe", function() {
    var tempVar;

    beforeEach(function() {
      tempVar = 4.6;
    });

    it("gVar is global scope, tempVar is this describe scope.", function() {
      expect(gVar).toEqual(tempVar);
    });
  });
});

跳過測試代碼塊

Suites 和 Specs 分別能夠用 xdescribe 和 xit 方法來禁用。運行時,這些 Suites 和 Specs 會被跳過,也不會在結果中出現。這能夠方便的在項目中能夠根據須要來禁用隱藏某些測試用例。

清單 8.測試用例
xdescribe("An example of xdescribe.", function() {
  var gVar;

  beforeEach(function() {
	gVar = 3.6;
	gVar += 1;
  });

  xit(" and xit", function() {
	expect(gVar).toEqual(4.6);
  });
});

以上代碼能夠在附件中的 List.html 運行,結果見下圖:

圖 2.測試用例結果

測試用例結果



與其餘工具的集成

Karma

在 Java 中,用 JUnit 作單元測試, 用 Maven 進行自動化單元測試;

一樣相對應的 JS 中,則能夠用 Jasmine 作單元測試,用 Karma 自動化完成單元測試。

Karma 做爲 JavaScript 測試執行過程管理工具,可用於測試全部主流 Web 瀏覽器。下面簡單介紹一下 Karma 與 Jasmine 的集成。

首先,下載安裝 Karma。

初始化 karma 配置文件 karma.conf.js。

安裝集成包 karma-jasmine。

修改 karma.conf.js 配置文件。

須要修改:files 和 exclude 變量。其中 autoWatch 設置爲 true,這樣若是修改測試文件並保存後,Karma 會檢測到而後自動執行。

module.exports = function (config) {
    config.set({
        basePath: '',
        frameworks: ['jasmine'],
        files: ['*.js'],
        exclude: ['karma.conf.js'],
        reporters: ['progress'],
        port: 9876,
        colors: true,
        logLevel: config.LOG_INFO,
        autoWatch: true,
        browsers: ['Chrome'],
        captureTimeout: 60000,
        singleRun: false
    });
};

啓動 karma,自動執行單元測試。

F:\Projects\karma>karma start karma.conf.js

另外,Jasmine 也能夠與持續集成工具 Jenkins 進行集成。



一個 Jasmine 的完整例子

Jasmine 在 JavaScript 中編譯,必須被包含在一個 JS 環境中,好比一個 web 網頁,來運行。JavaScript 被包含,經過一個<script>標籤,而後全部以上的 specs 能夠經過 Jasmine 計算和記錄。這樣 Jasmine 能夠運行全部這些 specs。此頁面被認爲是一個"runner"運行者。

下面經過一個具體的例子來介紹經過 runner 怎樣執行 Jasmine 的 suite。

首先,建立 HTMLReporter,Jasmine 調用它,來提供每一個 Spec 和 Suite 的結果。

報告負責展示結果給用戶。

代理爲報告過濾 specs。容許點擊某個結果中的 suites 或者 specs 來只運行 suite 的子集合。

當頁面完成加載時運行全部的測試-而後確認運行任何以前的 onload 句柄。

見下面清單 9,完整代碼示例見附件。

清單 9 .代碼示例
  <script type="text/javascript">	
	var jasmineEnv = jasmine.getEnv();
    	var htmlReporter = new jasmine.HtmlReporter();
		
    	jasmineEnv.addReporter(htmlReporter);
	  
	jasmineEnv.specFilter = function(spec) {
		return htmlReporter.specFilter(spec);
    	};	  
	
	window.onload = function() {
		jasmineEnv.execute();
    	};
  </script>

完整例子能夠在附件中的 Reporter.html 運行,結果見下圖:

圖 3.測試用例結果

測試用例結果



結語

經過本文的介紹,咱們能夠了解 Jasmine 的一些基本概念和用法,爲組織項目的測試打下基礎,爲項目代碼的可靠性和穩定性提供保證,並介紹了 Jasmine 和其餘框架的集成。Jasmine 的一些相對高級的用法和技巧,會在後續的文章中進行介紹。

相關文章
相關標籤/搜索