javascript单元测试框架jasmine

在jasmine的github官方主页进入releases后下载zip安装包,并解压。

目录结构(1个html文件和3个文件夹)

  1. lib:包含了测试运行案例所必需的文件,可以将不同版本的jasmine放在lib下,以便使用时切换
    • jasmine.js:整个框架的核心代码。
    • jasmine-html.js:用来展示测试结果的js文件。
    • boot.js:jasmine框架的启动脚本。这个文件放在jasmine.js之后,自己的测试js代码之前加载。
    • jasmine.css:用来美化测试结果。
  2. spec存放测试脚本。
    • PlayerSpec.js:就是针对src文件夹下的Player.js所写的测试用例。
      *SpecHelper.js:用来添加自定义的检验规则,如果框架本身提供的规则(诸如toBe,toNotBe等)不适用,就可以额外添加自己的规则(在本文件中添加了自定义的规则toBePlaying)。
  3. src存放需要测试的js文件。
  4. specRunner.html运行测试用例的环境,他将上面3个文件的主要内容都包含进来,如果要添加自己的测试,则修改相应的路径。

其中spec文件夹,src文件夹和specRunner.html文件是jasmine提供的一个完整实例,运行specRunner.html文件,在浏览器可看到运行结果。

specRunner.html



  
  Jasmine Spec Runner v2.2.0

  
  

  
  
  

  
  
  

  
  
  



核心概念

1. suites

suites 表示一个测试集,以函数describe(string,function)他包含俩个参数

  • string:测试组名称
  • function:测试组函数
    ** 一个suites(describe)包含多个specs(it),一个specs包含多个断言(expect)。

2. setup和teardown操作

jasmine的setup和teardown操作(setup是在每个测试用例spec执行之前做一些初始化操作,teardown是在每个测试用例spec执行之后做些清理操作,是由一组全局函数beforeEach afterEach beforeAll afterAll来实现的。

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

3. this

除了在describe函数开始定义变量,用于各it函数共享数据外,还可以通过this关键字来共享数据。
在在每一个Spec的生命周期(beforeEach->it->afterEach)的开始,都将有一个空的this对象(在开始下一个Spec周期时,this会被重置为空对象)。

4. 嵌套suites(describe的嵌套)

describe函数可以嵌套,每层都可以定义Specs。这样就可以让一个Suite由一组树状的方法组成。
每个嵌套的describe函数,都可以有自己的beforeEach,afterEach函数。
在执行每个内层Spec时,都会按嵌套的由外及内的顺序执行每个beforeEach函数,所以内层Sepc可以访问到外层Sepc中的beforeEach中的数据。类似的,当内层Spec执行完成后,会按由内及外的顺序执行每个afterEach函数。

5. specs

specs表示测试用例,以it(string,function)函数来封装
  • string:测试用例名称
  • function:测试用例函数

6. Expectations(expect)

一个断言,以expect来表示,返回true或false。Expectation带实际值,它和表示匹配规则的Matcher链接在一起,Matcher带有期望值。只有当一个spec中的所有Expectations全为true时,这个spec才通过,否则失败。 **

7. Matchers

** Matchers实现断言的比较,将Expectation传入的实际值与Matchers传入的期望值做比较。**
*任何Matcher都能通过在expect调用Matcher前加上not来实现一个否定的断言(expect(a).not().toBe(false);)

  • toBe():相当于===;
  • toBeDefine():检查变量或属性是否已声明且赋初值。
  • toBenull():是否是null
  • toBeTruthy():如果转换为布尔型,是否为true
  • toBeLessThan():数值比较,小于
  • toBeGreaterThan():数值比较,大于
  • toEqual:相当于==
    一个新建的Object不是(not to be)另一个新建的Object,但是它们是相等(to equal)的。
    expect().not().toBe(); expect().toEqual();
  • toContain():数组中是否包含元素值,只能用于数组,不能用于对象。
  • toBeCloseTo():数值比较时定义精度,四舍五入后比较。
  • toHaveBeenCalled():
  • toHaveBeenCalledWith():
  • toMatch():安正则表达式匹配
  • toThrow():检验一个函数是否会抛出一个错误。

8. 自定义Matchers

自定义的本质是一个函数(参数可以为空),该函数返回一个毕包,该毕包的本质是一个compare函数,compare函数带俩个参数actual value,expected value,compare函数必须返回一个带pass属性的结果Object,pass属性是一个Boolean值,表示该Matcher的结果(为true表示该Matcher实际值与预期值匹配,为false表示不匹配),也就是说,实际值与预期值具体的比较操作的结果,存放于pass属性中。
最后测试输出的失败信息应该在返回结果Object中的message属性中来定义。

  toBeGoofy: function(util, customEqualityTesters) {
    return {
      compare: function(actual, expected) {
        if (expected === undefined) {
          expected = '';
        }
        var result = {};
        result.pass = util.equals(actual.hyuk, "gawrsh" + expected, customEqualityTesters);
        if (result.pass) {
          result.message = "Expected " + actual + " not to be quite so goofy";
        } else {
          result.message = "Expected " + actual + " to be goofy, but it was not very goofy";
        }
        return result;
      }
    };
  }
};

使用自定义的Matchers

  • 将该函数添加到一个特定的describe函数的beforeEach中,以便该describe函数中的所有Spec都能调用到它。但其他describe中并不能使用该Matcher。
beforeEach(function() {
  jasmine.addMatchers(customMatchers);
});
it("can take an 'expected' parameter", function() {
  expect({
    hyuk: 'gawrsh is fun'
  }).toBeGoofy(' is fun');
});
});
  • 将该函数添加到全局的beforeEach函数中,这样所有的Suites中的所有的Specs,都可以使用该Matcher。
beforeEach(function () {
  jasmine.addMatchers({
    toBePlaying: function () {
      // 自定义Matcher:toBePlaying
      return {
        //要返回的compare函数
        compare: function (actual, expected) {
          var player = actual;
          //compare函数中要返回的结果Object,这里是一个匿名Object,包含一个pass属性。
          return {
            pass: player.currentlyPlayingSong === expected && player.isPlaying
          }
        }
      };
    }
  });
});
//使用
describe("Player", function() {
  it("should be able to play a Song", function() {
    player.play(song);
    //demonstrates use of custom matcher
    expect(player).toBePlaying(song);
  });

  describe("when song has been paused", function() {
    it("should indicate that the song is currently paused", function() {
      // demonstrates use of 'not' with a custom matcher
      expect(player).not.toBePlaying(song);
    });
)};

9. 禁用suites

  • 在describe之前添加×即可禁用suite,禁用后执行会跳过suite(describe),结果也不会显示在结果集。
    xdescribe("A spec", function() {}

10. 挂起specs

即将spec标记为Pending,结果是不执行,但在结果集中显示spec的名字,只是标记为Pending。

  • 如果在Spec函数it的函数名之前添加x(xit),那么该Spec就会被标记为Pending。
  • 一个没有定义函数体的Sepc也会在结果集中被标记为Pending。
  • 如果在Spec的函数体中调用pending()函数,那么该Spec也会被标记为Pending。pending()函数接受一个字符串参数,该参数会在结果集中显示在PENDING WITH MESSAGE:之后,作为为何被Pending的原因。

  xit("can be declared 'xit'", function() {
    expect(true).toBe(false);
  });

  it("can be declared with 'it' but without a function");
  
  it("can be declared by calling 'pending' in the spec body", function() {
    expect(true).toBe(false);
    pending('this is why it is pending');
  });
});

高级特性

1. spy

能监测任何function的调用和方法参数的调用痕迹。需使用2个特殊的Matcher:

  • toHaveBeenCalled():检查function是否被调用过。
  • toHaveBeenCalledWith():检查传入的参数是否被作为参数调用过。
    **使用spyOn(obj,'function')来为obj的function方法声明一个Spy。不过要注意的一点是,对Spy函数的调用并不会影响真实的值。
  beforeEach(function() {
    foo = {
      setBar: function(value) {
        bar = value;
      }
    };
  spyOn(foo, 'setBar');

2. and.callThrough()

如果在spyOn之后链式调用and.callThrough,那么Spy除了跟踪所有的函数调用外,还会直接调用函数额真实实现,因此Spy返回的值就是函数调用后实际的值
spyOn(foo, 'getBar').and.callThrough();

3. and.stub

在调用and.callThrough后,如果你想阻止spi继续对实际值产生影响,你可以调用and.stub。也就是说,and.stub是将spi对实际实现的影响还原到最终的状态——不影响实际值。

foo.setBar(123);
// 实际的bar=123
expect(bar).toEqual(123);
// 调用and.stub()后,之后调用foo.setBar将不会影响bar的值。
foo.setBar.and.stub();

全局匹配谓词

  1. jasmine.any()
    jasmine.any的参数为一个构造函数,用于检测该参数是否与实际值所对应的构造函数相匹配。
    expect(foo).toHaveBeenCalledWith(jasmine.any(Number), jasmine.any(Function));
  2. jasmine.anything()
    jasmine.anything用于检测实际值是否为null或undefined,如果不为null或undefined,则返回true。
it("matches anything", function() {
    expect(1).toEqual(jasmine.anything());
});
  1. jasmine.objecctConntaining()
    用于检测实际Object值中是否存在特定key/value对。
var foo;
  beforeEach(function() {
    foo = {
      a: 1,
      b: 2,
      bar: "baz"
    };
  });
  it("matches objects with the expect key/value pairs", function() {
    expect(foo).toEqual(jasmine.objectContaining({
      bar: "baz"
    }));
    expect(foo).not.toEqual(jasmine.objectContaining({
      c: 37
    }));
  });
  1. jasmine.arrayContaining()
    用于检测实际Array值中是否存在特定值
var foo;
  beforeEach(function() {
    foo = [1, 2, 3, 4];
  });
  it("matches arrays with some of the values", function() {
    expect(foo).toEqual(jasmine.arrayContaining([3, 1]));
    expect(foo).not.toEqual(jasmine.arrayContaining([6]));
  });

你可能感兴趣的:(javascript单元测试框架jasmine)