一、简介

Jasmine是一个用于测试JavaScript代码的行为驱动开发框架,它不依赖于任何其他JavaScript框架,也不需要DOM,它的语法简单明了,可以轻松地上手编写测试。

二、安装

  • 安装

执行 npm install jasmine --save-dev

  • 配置

在项目的package.json中设置test script:

"script": { "test": "jasmine" }

或者在npm init时直接设置test script:

{
  "name": "study-jasmine",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "jasmine"
  },
  "author": "albert",
  "license": "ISC",
  "devDependencies": {
    "jasmine": "^2.8.0"
  }
}

三、初始化项目并生成样例

通过创建一个spec目录和jasmine的配置文件jasmine.json初始化jasmine项目。

  • 初始化

jasmine init

此命令执行完之后会生成 spec\support\jasmine.json 文件:

{
	"spec_dir": "spec",
	"spec_files": [
		"**/*[sS]pec.js"
	],
	"helpers": [
		"helpers/**/*.js"
	],
	"stopSpecOnExpectationFailure": false,
	"random": false
}
说明:
`spec_dir`: 测试用例(spec)目录,自定义的目录必须相对于此路径
`spec_files`: 测试用例(spec)文件,路径相对于spec_dir配置的目录路径
`helpers`: 测试用例执行前文件,路径相对于spec_dir配置的目录路径
`stopSpecOnExpectationFailure`: it函数中的第一个期望失败后停止执行
`random`: 使用半随机(semi-random)顺序运行测试用例
备注:执行此命令需要确定已全局安装jasmine(npm install jasmine -g)
  • 生成样例文件

jasmine examples

四、运行测试

使用 jasminenpm test 运行测试,或者指定运行单个spec文件:jasmine spec/jasmine_examples/PlayerSpec.js

五、样例分析

jasmine examples命令执行后生成了以下目录/文件:

lib\jasmine_examples:Player.js 、 Song.js
spec\helpers\jasmine_examples: SpecHelper.js
spec\jasmine_examples\PlayerSpec.js

1、Song.js

一个简单的歌曲类,只有一个“标记为喜欢歌曲”的方法。

function Song() {
}

Song.prototype.persistFavoriteStatus = function(value) {
  // something complicated
  throw new Error("not yet implemented");
};

module.exports = Song;

2、Player.js

播放器类,共有四个方法:播放、暂停、继续、标记为喜欢。

function Player() {
}
Player.prototype.play = function(song) {
  this.currentlyPlayingSong = song;
  this.isPlaying = true;
};

Player.prototype.pause = function() {
  this.isPlaying = false;
};

Player.prototype.resume = function() {
  if (this.isPlaying) {
    throw new Error("song is already playing");
  }

  this.isPlaying = true;
};

Player.prototype.makeFavorite = function() {
  this.currentlyPlayingSong.persistFavoriteStatus(true);
};

module.exports = Player;

3、SpecHelper.js

此js中调用了beforeEach方法,beforeEach方法在describe(见PlayerSpec.js)中的每个测试用例(Spec)执行前执行,与之相对的是afterEach方法是在每个测试用例执行后执行。

此js在beforeEach的回调中使用addMatchers方法添加了自定义匹配器(matcher),定义toBePlaying的判断规则,此方法需要返回一个compare函数,compare函数将在检查期望值时被调用,compare函数接收的第一个参数是expect()函数的参数(actual),第二个参数(可选)是toBePlaying函数被调用时传的参数。compare函数必须返回一个包含pass属性(boolean类型)的对象,此属性值表明匹配的结果;还可以在返回对象中增加message属性自定义匹配结果信息。

beforeEach(function () {
  jasmine.addMatchers({
    toBePlaying: function () {
      return {
        compare: function (actual, expected) {
          var player = actual;
          return {
            pass: player.currentlyPlayingSong === expected && player.isPlaying
          }
        }
      };
    }
  });
});

4、PlayerSpec.js

此文件是Player.js的测试用例文件,共有五个测试用例。

describe("Player", function() {
  var Player = require('../../lib/jasmine_examples/Player');
  var Song = require('../../lib/jasmine_examples/Song');
  var player;
  var song;

  beforeEach(function() {
    player = new Player();
    song = new Song();
  });

  it("should be able to play a Song", function() {
    player.play(song);
    expect(player.currentlyPlayingSong).toEqual(song);
    //demonstrates use of custom matcher
    expect(player).toBePlaying(song);
  });

  describe("when song has been paused", function() {
    beforeEach(function() {
      player.play(song);
      player.pause();
    });

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

    it("should be possible to resume", function() {
      player.resume();
      expect(player.isPlaying).toBeTruthy();
      expect(player.currentlyPlayingSong).toEqual(song);
    });
  });

  // demonstrates use of spies to intercept and test method calls
  it("tells the current song if the user has made it a favorite", function() {
    spyOn(song, 'persistFavoriteStatus');
    player.play(song);
    player.makeFavorite();
    expect(song.persistFavoriteStatus).toHaveBeenCalledWith(true);
  });

  //demonstrates use of expected exceptions
  describe("#resume", function() {
    it("should throw an exception if song is already playing", function() {
      player.play(song);
      expect(function() {
        player.resume();
      }).toThrowError("song is already playing");
    });
  });
});
  • 说明:

    • describe(description, specDefinitions):

      定义一组测试用例(测试集suite),第一个参数是suite的描述,第二个参数是执行内部定义的测试集(suites)和测试用例(specs)的函数。

    • it(description, testFunctionopt, timeoutopt)

      定义单个的测试用例(spec),一个测试用例包含一个或多个期望来测试代码的正确性。第一个参数是测试用例的描述,第二个参数是对代码测试的函数,第三个参数是对异步测试用例的超时时间。

    • expect(actual)

      为测试用例创建一个期望。

附: