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 的一些相对高级的用法和技巧,会在后续的文章中进行介绍。

相关文章
相关标签/搜索