Jasmine入门(上)

什么是Jasmine

Jasmine是一个Javascript的BDD(Behavior-Driven Development)测试框架,不依赖任何其他框架。

如何使用Jasmine

从Github上(https://github.com/pivotal/jasmine/releases)下载所需的Jasmine版本。下载完成之后,直接打开SpecRunner.html即为Demo,除了引入Jasmine框架之外,只需引用自己所需测试的js文件以及Jasmine测试脚本引可。

图1:

基本语法介绍

describe(string, function):可以理解为是一个测试集或者测试包(为了便于称呼,我们本文中统一叫测试集,官方称之为suite),主要功能是用来划分单元测试的,describe是可以嵌套使用的

  • 参数string:描述测试包的信息
  • 参数function:测试集的具体实现

it(string, function):测试用例(官方称之为spec)

  • 参数string:描述测试用例的信息
  • 参数function:测试用例的具体实现

expect:断言表达式

第一个Jasmine例子

Step 1:

我们先创建一个名为myFirstJasmineTest.js的文件。

Step 2:

在Html页面中同时引用jasmine的框架文件与myFirstJasmineTest.js文件,可参考上面的图1。

Step 3:

在myFirstJasmineTest.js文件中添加如下内容:

 1 describe("My first Jasmine test", function() {
 2   it("a spec with an expectation", function() {
 3     expect(1).toBe(1);
 4     expect(1===1).toBe(true);
 5     expect(‘a‘).not.toBe(‘b‘);
 6   });
 7
 8   it("an other spec in current suite", function() {
 9       expect(true).toBe(true);
10   });
11 });
12
13 describe("My first Jasmine test", function() {
14   it("nothing", function() {
15   });
16 });

打开Html页面,Jasmine将自动执行用例:

图2:

从上述例子中我们可以看出:

  • 每个测试文件中可以包含多个describe
  • 每个describe中可以包含多个it
  • 每个it中可以包含多个expect

当然实际上,Jasmine还允许describe的嵌套使用,大家可以自行试试。

expect的使用

首先说一下,所有的expect都可以使用not表示否定的断言。

toBe:基本类型判断

  it("toBe and not.toBe", function() {
    expect(1).toBe(1);
    expect(‘a‘).not.toBe(‘b‘);
  });

toEqual: toEqual有两种用法,对于基本的类型,toEqual相当于toBe

  it("toEqual and not.toEqual for basic types", function(){
    expect(1).toEqual(1);
    expect(‘a‘).not.toEqual(‘b‘);
  })

toEqual还可以用来判断对象:

  it("toEqual and not.toEqual for objects", function(){
    var o1 = {
        name: "Jack",
        age: 12
    };

    var o2 = {
        name: "Jack",
        age: 12
    };

    var o3 = {
        name: "Tom",
        age: 13
    };

    expect(o1).toEqual(o2);
    expect(o1).not.toEqual(o3);
  })

toMatch: 使用正则表达式判断

  it("toMatch and not.toMatch", function(){
    var str = "Michael Jackson";

    expect(str).toMatch(/michael/i);
    expect(str).not.toMatch(/tom/i);
  })

toBeDefine: 判断是否是undefined

  it("toBeDefined and not.toBeDefined", function(){
    var student = {
        name: "Jack",
        age: 12
    };

    expect(student.name).toBeDefined();
    expect(student.gender).not.toBeDefined();
  })

toBeUndefined: 判断是否是undefined,与toBeDefine相反

  it("toBeUndefined and not.toBeUndefined", function(){
    var student = {
        name: "Jack",
        age: 12
    };

    expect(student.gender).toBeUndefined();
    expect(student.name).not.toBeUndefined();
  })

toBeNull:判断是否是null

  it("toBeNull and not.toBeNull", function(){
    var student = {
        name: "Jack",
        age: 12,
        deskmate: null
    };

    expect(student.deskmate).toBeNull();
    expect(student.name).not.toBeNull();
  });

toBeTruthy:判断是否能转换成bool型,判断的是否是True

  it("toBeTruthy and not.toBeTruthy", function(){
    var stu1;
    var stu2 = "Tom";

    expect(true).toBeTruthy();
    expect(stu2).toBeTruthy();
    expect(stu1).not.toBeTruthy();
    expect(undefined).not.toBeTruthy();
  });

toBeTruthy:判断是否能转换成bool型,判断的是否是False

  it("toBeFalsy and not.toBeFalsy", function(){
    var stu1;
    var stu2 = "Tom";

    expect(true).not.toBeFalsy();
    expect(stu1).toBeFalsy();
    expect(stu2).not.toBeFalsy();
    expect(undefined).toBeFalsy();
  });

toContain: 判断集合是否包含(可以是普通类型,和可以是对象)

  it("toContain and not.toContain", function(){
    var arrStr = ["Jack", "Tom", "Mary"];
    var arrObj = [{name:"Jack",age:21}, {name:"Tom",age:22}];

    expect(arrStr).toContain("Jack");
    expect(arrStr).not.toContain("jack");

    expect(arrObj).toContain({name:"Jack",age:21});
    expect(arrObj).not.toContain({name:"jack",age:21});
  });

toBeLessThan: 判断值类型的大小,结果若小则为True(也可以判断字符及字符串,以ascii码的大小为判断依据)

  it("toBeLessThan and not.toBeLessThan", function(){
    expect(1).toBeLessThan(1.1);
    expect("b").not.toBeLessThan("a");
  });

toBeGreaterThan: 判断值类型的大小,结果若大则为True,与toBeLessThan相反(也可以判断字符及字符串,以ascii码的大小为判断依据)

  it("toBeGreaterThan and not.toBeGreaterThan", function(){
    expect(1).not.toBeGreaterThan(1.1);
    expect("b").toBeGreaterThan("a");
  });

toBeCloseTo:判断数字是否相似(第二个参数为小数精度,默认为2位)

  it("toBeCloseTo and not.toBeCloseTo", function(){
    var a = 1.1;
    var b = 1.5;
    var c = 1.455;
    var d = 1.459;

    expect(a).toBeCloseTo(b, 0);
    expect(a).not.toBeCloseTo(c, 1);
    expect(c).toBeCloseTo(d);
  });

toThrow: 判断是否抛出异常

  it("toThrow and not.toThrow", function(){
    var foo = function() {
      return 1 + 2;
    };
    var bar = function() {
      return a + 1;
    };

    expect(foo).not.toThrow();
    expect(bar).toThrow();
  });

toThrowError: 判断是否抛出了指定的错误

  it("toThrowError and not.toThrowError", function() {
    var foo = function() {
      throw new TypeError("foo bar baz");
    };

    expect(foo).toThrowError("foo bar baz");
    expect(foo).toThrowError(/bar/);
    expect(foo).toThrowError(TypeError);
    expect(foo).toThrowError(TypeError, "foo bar baz");
  });

Setup和Teardown

Jasmine允许在执行测试集/测试用例的开始前/结束后做一些初始化/销毁的操作。

Setup方法:

  • beforeAll:每个suite(即describe)中所有spec(即it)运行之前运行
  • beforeEach:每个spec(即it)运行之前运行

Teardown方法:

  • afterAll:每个suite(即describe)中所有spec(即it)运行之后运行
  • afterEach:每个spec(即it)运行之后运行

示例代码:

 1 (function(){
 2     var globalCount;
 3     describe("Setup and Teardown suite 1", function() {
 4       var suiteGlobalCount;
 5       var eachTestCount;
 6
 7       beforeAll(function() {
 8         globalCount = 0; // 试试注释这行代码,看看对运行结果的影响
 9         suiteGlobalCount = 0;
10         eachTestCount = 0;
11       });
12
13       afterAll(function() {
14         //globalCount = 0; // 试试取消这行代码的注释,看看对运行结果的影响
15         suiteGlobalCount = 0;
16       });
17
18       beforeEach(function() {
19         globalCount++;
20         suiteGlobalCount++;
21         eachTestCount++;
22       });
23
24       afterEach(function() {
25         eachTestCount = 0;
26       });
27
28       it("Spec 1", function() {
29         expect(globalCount).toBe(1);
30         expect(suiteGlobalCount).toBe(1);
31         expect(eachTestCount).toBe(1);
32       });
33
34       it("Spec 2", function() {
35         expect(globalCount).toBe(2);
36         expect(suiteGlobalCount).toBe(2);
37         expect(eachTestCount).toBe(1);
38       });
39     });
40
41     describe("Setup and Teardown suite 2", function() {
42       beforeEach(function() {
43         globalCount += 2;
44       });
45
46       it("Spec 1", function() {
47         expect(globalCount).toBe(4);
48       });
49     });
50 })();

示例中的第一个describe,在beforeAll中初始化了各个计数变量,在beforeEach中设置每次执行it后,各个计数变量自增1,在afterAll中,重置了全局性的计数变量(尝试取消afterAll中对globalCount的注释,看看运行结果的变化),在afterEach中,重置了局部计数变量。

第二个describe,在beforeEach中对全局变量globalCount自增2,上述代码中,第一个describe中afterAll中没有对globalCount进行重置,因此执行完第一个describe后,globalCount的值为2,因此第二个describe的globalCount的初始值即为2。

在beforeEach/it/afterEach中,还可以使用this关键字定义变量,需要注意的是,使用this关键字声明的变量,仅在beforeEach/it/afterEach这个过程中传递:

 1 (function(){
 2     describe("Test ‘this‘", function() {
 3       beforeEach(function() {
 4         this.testCount = this.testCount || 0;
 5         this.testCount++;
 6       });
 7
 8       afterEach(function() {
 9         //this.testCount = 0; //无论是否有这行,结果是一样的,因为this指定的变量只能在每个spec的beforeEach/it/afterEach过程中传递
10       });
11
12       it("Spec 1", function() {
13         expect(this.testCount).toBe(1);
14       });
15
16       it("Spec 2", function() {
17         expect(this.testCount).toBe(1);
18       });
19     });
20 })();

xdescribe/xit的使用

在实际项目中,需要由于发布的版本需要选择测试用例包,xdescribe和xit能很方便的将不包含在版本中的测试用例排除在外。不过xdescribe和xit略有不同:

  • xdescribe:该describe下的所有it将被忽略,Jasmine将直接忽略这些it,因此不会被运行
  • xit:运行到该it时,挂起它不执行
 1 (function(){
 2     xdescribe("Test xdescribe", function() {
 3       it("Spec 1", function() {
 4         expect(1).toBe(1);
 5       });
 6
 7       it("Spec 2", function() {
 8         expect(2).toBe(2);
 9       });
10     });
11
12     describe("Test xit", function() {
13       it("Spec 1", function() {
14         expect(1).toBe(1);
15       });
16
17       xit("Spec 2", function() {
18         expect(2).toBe(1);
19       });
20
21       xit("Spec 3", function() {
22         expect(3).toBe(3);
23       });
24     });
25 })();

运行结果:

篇幅和精力原因,关于Jasmine的入门学习,我们将在下一篇中继续。

这里随便扯几句,最近由于新项目开始了,我在项目中同时需要担任PM、BA、开发的角色(哦,对了,我忘了告诉你们,其实我是.net的程序员),确实非常累, 很多东西要学、要做。不过对于技术的热爱(虽然技术不咋滴),我希望不管多忙多累,还是能在技术的道路上继续走下去。大家如果觉得我写的文章还可以,甚至能给你们带来一些小小的收获,希望大家顶一下,给我加加油。 好了,又到凌晨一点半了,我赶紧去睡了,明天还要去客户现场呢。

参考资料

Jasmine: http://jasmine.github.io/

粉丝日志:http://blog.fens.me/nodejs-jasmine-bdd/

时间: 2024-11-10 10:47:44

Jasmine入门(上)的相关文章

Jasmine入门(下)

上一篇 Jasmine入门(上) 介绍了Jasmine以及一些基本的用法,本篇我们继续研究Jasmine的其他一些特性及其用法(注:本篇中的例子均来自于官方文档). Spy Spy用来追踪函数的调用历史信息(是否被调用.调用参数列表.被请求次数等).Spy仅存在于定义它的describe和it方法块中,并且每次在spec执行完之后被销毁. 示例1: 1 (function(){ 2 describe("A spy", function() { 3 var foo, bar = null

网易云课堂_C++程序设计入门(上)_第2单元:丹青画松石– EGE图形库_第2节:一个简单的EGE程序

网易云课堂_C++程序设计入门(上)_第2单元:丹青画松石– EGE图形库_第2节:一个简单的EGE程序 #ifndef _GRAPHICS_H_ #define _GRAPHICS_H_ #ifndef __cplusplus #error You must use C++ compiler, or you need filename with '.cpp' suffix #endif #include "ege.h" using namespace ege; #endif #inc

Jasmine入门

本文是jasmine学习整理文章.适合入门,是作者参考了网上三篇文章之后,自己整理的. 初学者可以百度进入jasmine官网,点击release菜单进入github的版本释放页面:https://github.com/jasmine/jasmine/releases:下载最近的版本.下载之后 目录结构解释一下: lib:存放了运行测试案例所必须的文件,其内包含jasmine-2.2.0文件夹.可以将不同版本的Jasmine放在lib下,以便使用时切换. jasmine.js:整个框架的核心代码.

网易云课堂_C++程序设计入门(上)_第1单元:C++概览_第1单元作业 - 写代码 - 互评 (难度:易)

第1单元作业 - 写代码 - 互评 (难度:易) 查看帮助 返回 提交作业(截止时间已过) 完成并提交作业 作业批改 互评训练 互评作业 自评作业 成绩公布 查看成绩 温馨提示:本次作业的提交截止时间已过,无法成功提交作业.你可以在输入框中输入答案作为练习,但是所有答案都不会计入最后成绩. 请你练习编写一个C++程序,体会C++程序与C程序的不同之处.由于本作业需要同学们互评,因此作业提交时间期限很短,在题目发布后一周内就必须提交完成.超时的同学将无本次测验成绩,不参加互评会导致成绩被扣分.

Shell 脚本入门--上

大家好!今天分享的是一些shell脚本的基础知识,分篇为大家介绍,本篇介绍内容有:变量(分类.赋值.查询.引用).算数运算的实现. shell脚本简介 计算机高级语言分为两种类型,一种是面向对象型(如java.c#).一种是面向过程型(如shell.python).性质上的区别在于面向对象型试用于大型复杂的环境,可以更加精确细致的提供服务,缺点就是语法结构繁琐且严谨.而面向过程的语言,简单便捷好上手,但是不适用于复杂的环境.打个比方:现在有个大型的机械项目,一位经验丰富的老设计师,带着几位年轻的

Flask入门-上传的问题

flask.py from flask import Flask, render_template, request, redirect, url_for from werkzeug.utils import secure_filename from os import path app = Flask(__name__) @app.route('/') def hello_world():     return render_template('index.html', title='Welc

TensorFlow 入门 上(自用)

下文会出现的一些知识点:TensorFlow的计算模型.数据模型.运行模型,TensorFlow的工作原理. 两个重要概念--Tensor和Flow: Tensor是张量,在TensorFlow中可以简单理解为多维数组. Flow是流,表示张量之间通过计算相互转化的过程. TensorFlow 计算模型--计算图: TensorFlow是一个通过计算图的形式来表述计算的编程系统,每一个计算都是计算图上的一个节点,节点之间的边是计算之间的依赖关系. TensorFlow程序一般可分为两个阶段.一,

NPOI 入门--上传excel文件并解析

NPOI 2.4.1 首先去设置下webconfig里面上传文件大小的设置, <httpRuntime targetFramework="4.5" maxRequestLength="102400" executionTimeout="3600"  />,我设置了允许上传最大100M. 话不多说,上MVC 后台代码: /// <summary> /// 上传文件,上传实体文件 /// </summary> //

C++程序设计入门(上) 之对象和类

面向对象编程: 如何定义对象?  同类型对象用一 个通用的类来定义 class C { int p; int f(); }; C ca, cb; 一个类用变量来定义数据域,用函数定义行为. class Cirle { public: double r; Cirle() { r = 1; } Cirle(double newr){ r = newr; } double get() { return r * r *3.14; } }; 构造函数: 类中有 一种特殊的“构造函数”,在创建对象时被自动调