mocha测试框架学习

mocha是一个运行在Node和浏览器中的功能非常强大并易于异步测试的框架。它串行执行,并支持灵活精确的报告,将未捕获的异常映射到正确的测试用例中。

安装


  • 全局安装
    $npm install -g mocha
  • 作为项目开发依赖安装
    $npm install --save-dev mocha

入门


$mkdir test
$vim test/test.js

在vim中编辑:

var assert = require('assert');
describe('Array', function() {
     describe('#indexOf()', function() {
         it('should return -1 when the value is not present', function() {
             assert.equal(-1, [1,2,3].indexOf(4));
         });
     });
});

在terminal中执行:

$./node_modules/mocha/bin/mocha
Array
  #indexOf() ✓
    should return -1 when the value is not present 
1 passing (9ms)

在package.json中设置测试脚本:

"scripts":  {
     "test":  "mocha"
 }

运行test:

$npm test

异步代码


使用mocha测试异步代码相当简单,只需要在it()中添加一个callback(通常我们命名为done),mocha便会在测试时等待这个函数来完成测试。

describe('User', function() {
  describe('#save()', function() { 
    it('should save without error', function(done) { 
      var user = new User('Luna');
      user.save(done);
    });
  });
});

Promise


mocha不仅可以使用done回调,还可以返回一个promise。

beforeEach(function() { 
    return db.clear() 
        .then(function() {
            return db.save([tobi, loki, jane]);
        });
});

describe('#find()', function() {
    it('respond with matching records', function() { 
        return db.find({ type: 'User' }).should.eventually.have.length(3);
    });
});

同步代码


测试同步代码时,没有回调函数,mocha会自动继续执行下一个测试。

describe('Array', function() { 
    describe('#indexOf()', function() {
        it('should return -1 when the value is not present', function() { 
            [1,2,3].indexOf(5).should.equal(-1);
            [1,2,3].indexOf(0).should.equal(-1); 
        });
    });
});

钩子(HOOKS)


默认接口风格为“BDD”,因此mocha提供了before(),after(),beforeEach(),afterEach()
四个钩子方法。这几个方法可以用来设置先决条件或清除测试条件。

describe('hooks', function() { 
    before(function() {
        // runs before all tests in this block 
    });
    after(function() { 
    // runs after all tests in this block 
    }); 
    beforeEach(function() { 
    // runs before each test in this block 
    }); 
    afterEach(function() { 
    // runs after each test in this block 
    });
   // test cases
});

测试代码可以散布在任意位置,但执行顺序为:
before() > beforeEach() > Tests > afterEach() > after()

Describing Hooks

所有的钩子都可以指定一个description选项运行,以使得mocha可以在运行时更容易地指出错误,如果钩子是一个给定名称的函数,那么将会使用函数名。

beforeEach(function namedFun() { 
    // beforeEach:namedFun
});
beforeEach('some description', function() { 
    // beforeEach:some description
});
异步钩子

所有的钩子可以使同步的也可以使异步的。

describe('Connection', function() { 
    var db = new Connection,
    tobi = new User('tobi'),
    loki = new User('loki'), 
    jane = new User('jane'); 
    beforeEach(function(done) { 
        db.clear(function(err) { 
            if (err) return done(err);
            db.save([tobi, loki, jane], done); 
        }); 
    }); 
    describe('#find()', function() { 
        it('respond with matching records', function(done) { 
            db.find({type: 'User'}, function(err, res) { 
                if (err) return done(err);
                res.should.have.length(3);
                done();
            }); 
        }); 
    });
});

Pending测试


describe('Array', function() { 
    describe('#indexOf()', function() { 
        // pending test below it('should return -1 when the value is not present'); 
    });
});

Exclusive测试


Exclusive通过为函数加上 .only 执行特定的一组测试用例。

describe('Array', function() {
  describe.only('#indexOf()', function() {
    it.only('should return -1 unless present', function() {
      // this test will be run
    });

    it('should return the index when present', function() {
      // this test will not be run
    });
  });
});

如果出现钩子,那么它依然会被执行

Inclusive测试


与Exclusive相反,使用 .skip 会让mocha忽略一组测试用例。

describe('Array', function() {
  describe('#indexOf()', function() {
    it.skip('should return -1 unless present', function() {
      // this test will not be run
    });

    it('should return the index when present', function() {
      // this test will be run
    });
  });
});

Retry测试


可以指定次数让失败的测试重试。主要用于端对端测试,不要用于单元测试。
重试会重新执行beforeEach/afterEach 钩子,但不会执行before/after**。

describe('retries', function() {
  // Retry all tests in this suite up to 4 times
  this.retries(4);

  beforeEach(function () {
    browser.get('http://www.yahoo.com');
  });

  it('should succeed on the 3rd try', function () {
    // Specify this test to only retry up to 2 times
    this.retries(2);
    expect($('.foo').isDisplayed()).to.eventually.be.true;
  });
});

动态生成测试


使用 Function.prototype.call 和函数表达式动态生成测试集。

var assert = require('chai').assert;

function add() {
  return Array.prototype.slice.call(arguments).reduce(function(prev, curr) {
    return prev + curr;
  }, 0);
}

describe('add()', function() {
  var tests = [
    {args: [1, 2],       expected: 3},
    {args: [1, 2, 3],    expected: 6},
    {args: [1, 2, 3, 4], expected: 10}
  ];

  tests.forEach(function(test) {
    it('correctly adds ' + test.args.length + ' args', function() {
      var res = add.apply(null, test.args);
      assert.equal(res, test.expected);
    });
  });
});

得到如下的输出:

$ mocha

  add()
    ✓ correctly adds 2 args
    ✓ correctly adds 3 args
    ✓ correctly adds 4 args

Test Duration


mocha会在执行过程中展示执行周期,对于slow的测试用例,可以使用slow()方法调整。

describe('something slow', function() {
  this.slow(10000);

  it('should take long enough for me to go make a sandwich', function() {
    // ...
  });
});

Timeouts


Suite-Level

describe('a suite of tests', function() {
  this.timeout(500);

  it('should take less than 500ms', function(done){
    setTimeout(done, 300);
  });

  it('should take less than 500ms as well', function(done){
    setTimeout(done, 250);
  });
})
Test-Level

it('should take less than 500ms', function(done){
  this.timeout(500);
  setTimeout(done, 300);
});
Hook-Level

describe('a suite of tests', function() {
  beforeEach(function(done) {
    this.timeout(3000); // A very long environment setup.
    setTimeout(done, 2500);
  });
});

使用this.timeout(0)禁用所有timeout**

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容