Jasmine - 文档(一)

前言

实习期间接触很多新东西。最近又在学习如何写一个独立的测试单元。看了公司前人的代码,后来网上搜寻了相关的知识,打算还是将自己的理解简单写下来。

简介

Jasmine是一种JavaScript的测试框架,它不依赖于其他框架,也不依赖于DOM结构。其语法特点在于简单清晰,就算是刚入门没多久的JavaScript程序猿也能够写出简单的测试单元代码。

下载 & 部署

下载地址https://github.com/jasmine/jasmine/releases

环境部署

解压后,dist 下就是各个版本的独立运行包,解压最新的 2.x 版本,双击打开 SpecRunner.html 即可运行测试,注意要在SpecRunner.html 的 <head> 内引用 Jasmine 的 js 文件和测试文件。想简单使用的话,将 soucre/spec 下的测试文件替换成你自己的即可。

<!DOCTYPE HTML>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>Jasmine Spec Runner v2.0.0</title>
 
    <link rel="shortcut icon" type="image/png" href="lib/jasmine-2.0.0/jasmine_favicon.png">
    <link rel="stylesheet" type="text/css" href="lib/jasmine-2.0.0/jasmine.css">
 
    <script type="text/javascript" src="lib/jasmine-2.0.0/jasmine.js"></script>
    <script type="text/javascript" src="lib/jasmine-2.0.0/jasmine-html.js"></script>
    <script type="text/javascript" src="lib/jasmine-2.0.0/boot.js"></script>
 
    <!-- 被测试的代码 -->
    <script type="text/javascript" src="src/xxx.js"></script>
 
</head>
 
<body>
</body>

</html>

快速入门

<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8">
    <title></title>
    <script src="jquery-1.11.3.js"></script>
    <link rel="stylesheet" type="text/css" href="jasmine-2.8.0/jasmine.css">
    <script src="jasmine-2.8.0/jasmine.js"></script>
    <script src="jasmine-2.8.0/jasmine-html.js"></script>
    <script src="jasmine-2.8.0/boot.js"></script>
</head>

<body>
   
    <script>

        function get1() {
            $.getJSON("http://localhost:8080/test/get").then(function(result) {
                console.log(result);
            });
        }
        
        // 每一个测试用例的超时时间
        jasmine.DEFAULT_TIMEOUT_INTERVAL = 1000;
        
        // 请求的接口的前缀 // http://localhost:8080/test
        var base = "/ajaxserverapache";
        
        //测试模块
        describe("ajax", function() {
            // 测试方法
            it("get请求", function(done) {
                // 服务器返回的结果
                var result;
                
                $.getJSON(base + "/get").then(function(jsonObj) {
                    result = jsonObj;
                });
                
                // 由于是异步请求,需要使用setTimeout来校验
                setTimeout(function() {
                    expect(result).toEqual({
                        "data" : "get ok"
                    });
                    
                    // 校验完成,通知jasmine框架
                    done();
                }, 100);
            });
        });
    </script>
    
</body>

</html>

核心

Suites(describe)是Jasmine的核心,是一个测试集,里面包括多个specs(it),而每个specs里面可能包含多个断言(expect)。

1、Suites(describe)

Suites使用describe()来定义,其中传递两个参数为: 

  • string:用于描述测试组的名称 
  • function:是测试组的主体函数 

测试组的代码如下:

describe("This is a suite", function() {
  it("This is a specs", function() {
    var a = 'abc';
    expect(a).toEqual('abc');
  });
});

代码使用describe()函数定义了一个名为“This is a suite”的测试组,测试组的内容在于判断a是否等于“abc”,主体内容将在后面继续介绍。

为了能够在测试开始前先进行部分初始化,或者在测试结束后对一些内容进行销毁,主体还包括四个全局函数: 

  • beforeEach():在describe函数中每个Spec执行之前执行。 
  • afterEach():在describe函数中每个Spec数执行之后执行。 
  • beforeAll():在describe函数中所有的Specs执行之前执行,但只执行一次,在Sepc之间并不会被执行。 
  • afterAll():在describe函数中所有的Specs执行之后执行,但只执行一次,在Sepc之间并不会被执行。 

例如:

describe("This is a suite", function() {

  beforeEach(function(){
    var a = 'abc';
  });

  afterEach(function(){
    a = '';
  })

  it("This is a specs1", function() {
    expect(a).toEqual('abc');
  });

});

上述代码中,在每一个specs执行前都会声明变量a为“abc”,而在测试之后,都会将其置为空字符串。

2、嵌套describe

Suites可以嵌套定义,每层都可以包含自己的specs,并且进行测试。同样可以包含各自的beforeEach()afterEach()等函数。例如:

describe("This is the first describe", function() {
  var a;

  beforeEach(function() {
    a = 'abc';
  });

  afterEach(function() {
    a = '';
  });

  it("is just a function", function() {
    expect(a).toEqual('abc');
  });

  describe("This is the second describe", function() {
    var b;

    beforeEach(function() {
      b = 'abc';
    });

    it("is just a function too", function() {
      expect(b).toEqual(a);
    });
  });

});

3、Specs(it)

Specs是测试组里的每个测试体,其中用it()函数定义测试体,传递两个参数: 
string:用于描述测试体的名称 
function:测试体的主体内容 

如上一段代码中:

it("This is a specs", function() {
    expect(a).toEqual('abc');
});

则为一个测试体,当然,每个测试组Suites可以包含多个测试体,如下:

describe("This is a suite", function() {

  it("This is a specs1", function() {
    var a = 'abc';
    expect(a).toEqual('abc');
  });

  it("This is a specs2", function() {
    var b = {};
    expect(b).toBe({});
  });

  it("This is a specs3", function() {
    expect(c).toBeUndefined();
  });

});

代码定义了一个测试组 “This is a suite”,其中包括三个 specs,分别测试 a 是否等于 ‘abc’,b 是否和空对象一致,c 是否为undefined。

4、断言(expect)

Specs里面可能包含多个断言,只有在所有的断言都返回true时才会通过,否则测试失败。正如上面代码所示,expect(c).toBeUndefined();为一个测试语句,判断c变量是否为undefined。 

expect()传递一个参数,为actual,接收实际值,而后面紧跟着一个Matchers传递一个(或没有),来进行判断是否通过。如例子所示,c为实际值,而ToBeUndefined()则为Matchers,进行的比较则为c(实际值)是否为undefined。 
再比如:expect(a).toEqual('abc');传递的实际值为a,与“abc”进行判断是否相等。

注意:it函数块可以包含多个expect过程,只要有其中的expect不符合期望,it就会测试不通过;而describe也可以包含多个it,只要有中有一个it报错,那么describe就会测试不通过。

5、Matchers

Jasmine定义了多个Matchers,用来测试一些变量是否通过。

常见的有: 

  • toBe():判断两个变量是否全等,类似于“===”; 
  • toNotBe():与上一个相反,判断两个变量是否不全等,类似于“!==”; 
  • toBeDefined():检查变量或属性是否已声明且赋值; 
  • toBeUndefined():与上一个相反; 
  • toBeNull():判断变量是否为null; 
  • toBeTruthy():判断变量如果转换为布尔值,是否为true; 
  • toBeFalsy():与上一个相反; 
  • toBeLessThan():与数值比较,是否小于; 
  • toBeGreaterThan():与数值比较,是否大于; 
  • toEqual():判断变量是否相等,相当于“==”; 
  • toContain():判断一个数组中是否包含元素(值)。只能用于数组,不能用于对象; 
  • toBeCloseTo():数值比较时定义精度,先四舍五入后再比较; 
  • toMatch():按正则表达式匹配; 
  • toNotMatch():与上一个相反; 
  • toThrow():检验一个函数是否会抛出一个错误。
  • 注意:任何Matcher都能通过在expect调用Matcher前加上not来实现一个否定的断言(expect(a).not().toBe(false);)。 

常见的Matchers使用代码如下:

describe("Included matchers:", function() {

  it("The 'toBe' matcher compares with ===", function() {
    //toBe()类似于"==="
    var a = 12;
    var b = a;

    expect(a).toBe(b);//通过
    expect(a).not.toBe(null);//通过,因为a!==null
  });

  describe("The 'toEqual' matcher", function() {
    //toEqual()类似于"=="

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

    it("should work for objects", function() {
      var foo = {
        a: 12,
        b: 34
      };
      var bar = {
        a: 12,
        b: 34
      };
      expect(foo).toEqual(bar);//通过,两个对象属性和值都一样
    });
  });

  it("The 'toMatch' matcher is for regular expressions", function() {
    //toMatch()用于匹配正则表达式
    var message = "foo bar baz";

    expect(message).toMatch(/bar/);//通过,参数可以是正则表达式
    expect(message).toMatch("bar");//通过,参数可以是字符串
    expect(message).not.toMatch(/quux/);//通过,因为toMatch()匹配不到/quux/
  });

  it("The 'toBeDefined' matcher compares against `undefined`", function() {
    //toBeDefined()判断参数是否定义
    var a = {
      foo: "foo"
    };

    expect(a.foo).toBeDefined();
    expect(a.bar).not.toBeDefined();
  });

  it("The `toBeUndefined` matcher compares against `undefined`", function() {
    //toBeUndefined()判断参数是否为undefined
    var a = {
      foo: "foo"
    };

    expect(a.foo).not.toBeUndefined();
    expect(a.bar).toBeUndefined();
  });

  it("The 'toBeNull' matcher compares against null", function() {
    //toBeNull()判断参数是否为空
    var a = null;
    var foo = "foo";

    expect(null).toBeNull();
    expect(a).toBeNull();
    expect(foo).not.toBeNull();
  });

  it("The 'toBeTruthy' matcher is for boolean casting testing", function() {
    //toBeTruthy()判断参数转化为布尔值时是否为true
    var a, foo = "foo";

    expect(foo).toBeTruthy();//通过,foo变量转变为true
    expect(a).not.toBeTruthy();
  });

  it("The 'toBeFalsy' matcher is for boolean casting testing", function() {
    //toBeFalsy()判断参数转化为布尔值时是否为false
    var a, foo = "foo";

    expect(a).toBeFalsy();
    expect(foo).not.toBeFalsy();
  });

  it("The 'toContain' matcher is for finding an item in an Array", function() {
    //toContain()判断元素是否存在于数组内。不适用于对象
    var a = ["foo", "bar", "baz"];

    expect(a).toContain("bar");
    expect(a).not.toContain("quux");
  });

  it("The 'toBeLessThan' matcher is for mathematical comparisons", function() {
    //toBeLessThan()判断实际值是否小于期望值
    var pi = 3.1415926,
      e = 2.78;

    expect(e).toBeLessThan(pi);
    expect(pi).not.toBeLessThan(e);
  });

  it("The 'toBeGreaterThan' matcher is for mathematical comparisons", function() {
    //toBeGreaterThan()判断实际值是否大于期望值
    var pi = 3.1415926,
      e = 2.78;

    expect(pi).toBeGreaterThan(e);
    expect(e).not.toBeGreaterThan(pi);
  });

  it("The 'toBeCloseTo' matcher is for precision math comparison", function() {
    //toBeCloseTo()数值比较时定义精度,先四舍五入后再比较
    var pi = 3.1415926,
      e = 2.78;

    expect(pi).not.toBeCloseTo(e, 2);
    expect(pi).toBeCloseTo(e, 0);
  });

  it("The 'toThrow' matcher is for testing if a function throws an exception", function() {
  //toThrow()判断函数是否会抛出一个错误
    var foo = function() {
      return 1 + 2;
    };
    var bar = function() {
      return a + 1;
    };

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

  it("The 'toThrowError' matcher is for testing a specific thrown exception", function() {
    //toThrowError()判断函数是否抛出一个特别的错误,以下四种都能够通过测试
    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");
  });

});

6、自定义Matchers

当然,用户可以自定义Matchers。在beforeEach()it()函数里调用Jasmine.addMatchers(),其中可以传递一个参数expected作为测试值,而实际值则保存在this.actual中,代码如下:

describe("This is a suite", function() {

  beforeEach(function(){
    var a = 'abc';
    this.addMatchers({
      toBeTrue : function(expected){
        return this.actual==expected;
      }
    });
  });

  it("This is a specs1", function() {
    expect(a).toBeTrue('abc');
  });

});

代码在beforeEach()中调用this.addMatchers()定义了一个Matchers。定义了ToBeTrue(),传递一个参数expected与实际值作比较。 
后面调用该Matchers时,代码expect(a).toBeTrue('abc');中,a则为实际值(this.actual),而“abc”则为参数expected。 
该定义的Matchers与原有的toEqual()类似。

7、禁用Suites

通过调用xdescribe()函数可以禁用Suites。代码执行时,这些Suites以及里面的任何spec都将跳过,因而他们的结果也不会出现在最终的输出结果中。例如:

xdescribe("A spec", function() {

  var foo;

  beforeEach(function() {
    foo = 0;
    foo += 1;
  });

  it("is just a function, so it can contain any code", function() {
    expect(foo).toEqual(1);
  });

});

输出结果如图:

 

8、挂起Specs

被挂起的spec不会执行。但是他们的名字仍会显示在pending的结果集中。 

声明挂起的方式有三种: 

  1. spec可以使用xit()来声明挂起; 
  2. spec声明时不添加任何函数体也可以在结果中达到挂起的效果; 
  3. 如果你在spec体内的任何位置调用pending()函数,不管那个断言通过与否,该spec都将被挂起。当Suites结束后,pending所传递的字符串将被作为挂起的理由而显示。 

例如:

describe("Pending specs", function() {

  xit("can be declared 'xit'", function() {
    //使用xit()函数挂起
    expect(true).toBe(false);
  });


  it("can be declared with 'it' but without a function");
  //使用空函数体将spec挂起


  it("can be declared by calling 'pending' in the spec body", function() {
    expect(true).toBe(false);
    pending('this is why it is pending');    //调用pending()将其挂起
  });

});

最终显示结果为: 

9、this 关键字

除了在describe()声明变量外,另外一个在beforeEach()it()afterEach()之间共享变量的方法是使用this关键字。每一个spec的beforeEach()it()afterEach()拥有相同的在下个spec的beforeEach()it()afterEach()执行之前会延迟置空的空对象this

代码如下:

describe("A spec", function() {

  beforeEach(function() {
    this.foo = 0;
  });

  it("can use the `this` to share state", function() {
    expect(this.foo).toEqual(0);
    this.bar = "test pollution?";
  });

  it("prevents test pollution by having an empty `this` created for the next spec", function() {
    expect(this.foo).toEqual(0);
    expect(this.bar).toBe(undefined);
  });

});

代码在每个spec之前声明this.foo并赋值,在其it()函数里能够共享该变量。而在it()函数里声明的this.bar,在下一个spec执行时无法获得,此时两者的this关键字所指向的并不一致。

更多教程:Jasmine - 文档(二)

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

陆氪和他的那些代码

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值