Mocha入门

Mocha(发音"摩卡")诞生于2011年,是现在最流行的JavaScript测试框架之一,在浏览器和Node环境都可以使用。

它是是做单元测试的,类似的测试框架还有JasmineKarmaTape

MochaGithub地址

中文文档:https://mochajs.cn/(文档翻译有点问题,建议和原文对照读)

英文:https://mochajs.org/

mocha学习
阮一峰这篇写的很详细,看这篇就好:
http://www.ruanyifeng.com/blog/2015/12/a-mocha-tutorial-of-examples.html

什么是断言?

it('sum(1, 2, 3) should return 6', () => {
    assert.strictEqual(sum(1, 2, 3), 6);
})

所谓"断言",就是判断源码的实际执行结果与预期结果是否一致,如果不一致就抛出一个错误。上面这句断言的意思是,调用sum(1, 2, 3),结果应该等于6。
所有的测试用例(it块)都应该含有一句或多句的断言。它是编写测试用例的关键。断言功能由断言库来实现,Mocha本身不带断言库,所以必须先引入断言库。

assert是node内置的断言库

https://nodejs.org/api/assert.html

mocha主要拥有两个API,分别是describe和it。

describe

describe表示一个“测试组件”,描述了一组测试。它是一个函数,第一个参数是测试套件的名称("加法函数的测试"),第二个参数是一个实际执行的函数。

it

it表示一个单元测试(unit test),描述了一个具体的测试,是测试的最小单位。它也是一个函数,第一个参数是测试用例的名称("1 加 1 应该等于 2"),第二个参数是一个实际执行的函数。一个单元测试必须用到断言

开始编写测试

单元测试的文件应当全部放在test文件目录下,mocha默认会执行test目录下的所有测试,因此不要去改变默认目录。

通常,测试脚本与所要测试的源码脚本同名,但是后缀名为.test.js(表示测试)或者.spec.js(表示规格)。比如,hello.js的测试脚本名字就是hello.test.js

假设我们编写了一个hello.js,并且输出一个简单的求和函数:

// hello.js

module.exports = function (...rest) {
    var sum = 0;
    for (let n of rest) {
        sum += n;
    }
    return sum;
};

假如我们要对hello.js的函数进行测试,那么我们在test文件夹下新建一个hello.test.js,

const assert = require('assert');

const sum = require('../hello');

describe('#hello.js', () => {

    describe('#sum()', () => {
        it('sum() should return 0', () => {
            assert.strictEqual(sum(), 0);
        });

        it('sum(1) should return 1', () => {
            assert.strictEqual(sum(1), 1);
        });

        it('sum(1, 2) should return 3', () => {
            assert.strictEqual(sum(1, 2), 3);
        });

        it('sum(1, 2, 3) should return 6', () => {
            assert.strictEqual(sum(1, 2, 3), 6);
        });
    });
});

所有的测试用例(it块)都应该含有一句或多句的断言。它是编写测试用例的关键。

执行

mocha add.test.js

mocha命令后面紧跟测试脚本的路径和文件名,可以指定多个测试脚本。

$ mocha file1 file2 file3

Mocha默认运行test子目录里面的测试脚本。所以,一般都会把测试脚本放在test目录里面,然后执行mocha就不需要参数了。

Mocha默认只执行test子目录下面第一层的测试用例,不会执行更下层的用例。

为了改变这种行为,就必须加上--recursive参数,这时test子目录下面所有的测试用例----不管在哪一层----都会执行。

mocha --recursive

其默认“BDD”式接口,mocha提供钩before()after()beforeEach(),和afterEach()。这些应该用于设置前置条件并在测试后进行清理。

运行顺序:

所有before()钩子运行(一次)

然后任何beforeEach()钩子,测试,任何afterEach()钩子

最后after()钩子(一次)

多种写法:

beforeEach(function() {
  // beforeEach hook
});

beforeEach(function namedFun() {
  // beforeEach:namedFun
});

beforeEach('some description', function() {
  // beforeEach:some description
});

为啥最终都要return啥呢?

    before(() => {

      return driver

        .initWindow(MOBILE_OTPTIONS);

    });



    after(() => {

      return driver

        .openReporter(true)

        .quit();

    });

箭头功能

不鼓励将箭头函数(“lambdas”)传递给Mocha。Lambdas词法绑定this,无法访问Mocha上下文。例如,以下代码将失败:

describe('my suite', () => {
  it('my test', () => {
    // should set the timeout of this test to 1000 ms; instead will fail
    this.timeout(1000);
    assert.ok(true);
  });
});

如果您不需要使用 Mocha的上下文,lambdas应该可以工作。但是,如果最终需要,结果将更难以重构。

根级挂钩

您也可以选择任何文件并添加“root”级别挂钩。例如,beforeEach()在所有describe()块之外添加。这将导致回调beforeEach()在任何测试用例之前运行,无论它存在于哪个文件中(这是因为Mocha有一个隐含的 describe()块,称为“根套件”)。

beforeEach(function() {
  console.log('before every test in every file');
});

测试用例管理

.only()

如果有only,只有only的将被执行

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

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

  describe.only('#concat()', function () {
    it('should return a new Array', function () {
      // this test will also be run
    });
  });

  describe('#slice()', function () {
    it('should return a new Array', function () {
      // this test will not be run
    });
  });
});

注意:钩子(如果存在)仍将执行。

.skip()

.only()相反。通过附加.skip(),您可以告诉Mocha简单地忽略这些套件和测试用例。跳过的任何内容都将被标记为待处理,并按此报告。

describe.skip
it.skip
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
    });
  });
});

您也可以在运行时跳过使用this.skip()。如果测试需要预先无法检测到的环境或配置,则运行时跳过是合适的。例如:

it('should only test in the correct environment', function() {
  if (/* check test environment */) {
    // make assertions
  } else {
    this.skip();
  }
});

上述测试将报告为待定。同样重要的是要注意调用this.skip()将有效中止测试。

测试持续时间

很多的测试报告都会显示测试所花费的时间,同样也会对一些耗时的测试作出特殊的标记。

Mocha默认会高亮显示超过75毫秒的测试用例

image.png

可以用-s--slow调整这个参数。

$ mocha -t 5000 -s 1000 timeout.test.js

上面命令指定高亮显示耗时超过1000毫秒的测试用例。

也可以使用slow()方法来明确的表示出,超过多久的时间,这个测试就可以认为是slow的。

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

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

异步

Mocha默认每个测试用例最多执行2000毫秒,如果到时没有得到结果,就报错。对于涉及异步操作的测试用例,这个时间往往是不够的,需要用-t--timeout参数指定超时门槛。

it('测试应该5000毫秒后结束', function(done) {
  var x = true;
  var f = function() {
    x = false;
    expect(x).to.be.not.ok;
    done(); // 通知Mocha测试结束
  };
  setTimeout(f, 4000);
});
mocha -t 5000 timeout.test.js

上面命令将测试的超时时限指定为5000毫秒。

done函数。it块执行的时候,传入一个done参数,当测试结束的时候,必须显式调用这个函数,告诉Mocha测试结束了。否则,Mocha就无法知道,测试是否结束,会一直等到超时报错。

关于timeout也可不必在命令行中输入,可为单独的用例指定
this.timeout(500);
可在describe 和 it中调用

另外,Mocha内置对Promise的支持,允许直接返回Promise,等到它的状态改变,再执行断言,而不用显式调用done方法。请看promise.test.js

it('异步请求应该返回一个对象', function() {
return fetch('https://api.github.com')
 .then(function(res) {
   return res.json();
 }).then(function(json) {
   expect(json).to.be.an('object');
 });
});

接口

Mocha的“界面”系统允许开发人员选择他们的DSL风格。Mocha有BDDTDDExportsQUnitRequire -style接口。

TDD(Test-Driven Development)——测试驱动开发

根据客户需求编写测试用例,对功能的过程和接口都进行了设计,而且这种从使用者角度对代码进行的设计通常更符合后期开发的需求。因为关注用户反馈,可以及时响应需求变更,同时因为从使用者角度出发的简单设计,也可以更快地适应变化。

BDD(Behavior-Driven Development)——行为驱动开发

BDD采用更容易测试的软件需求描述方式,来鼓励需求分析人员、软件开发人员、测试人员密切协同开展软件产品研发工作。同时BDD工具可以帮助把用BDD风格描述的业务需求转换成自动化测试脚本,让软件开发人员同步验证自己编写的代码是否满足业务需求描述的产品特性,并在验证软件产品特性的同时形成软件产品特性文档。从而实现了产品研发文档与软件产品代码编写的同步更新

BDD

BDD接口提供describe()context()it()specify()before()after()beforeEach(),和afterEach()

context()只是一个别名describe(),行为方式相同; 它只是提供了一种让测试更容易阅读和组织的方法。同样,specify()是别名it()

所有前面的示例都是使用BDD接口编写的。

TDD

TDD接口提供suite()test()suiteSetup()suiteTeardown()setup(),和teardown()

mocha项目文件结构

在项目的根目录下,新建一个test文件夹。

└── test
├── config.json
├── helper.js
├── mocha.opts
└── render.test.js

测试文件放在test/文件夹中

test/mocha.opts文件为mocha命令行参数的默认值

test/目录

Mocha默认运行test子目录里面的测试脚本。

mocha.opts

"./test/mocha.opts"文件为mocha命令行参数的默认值

  • #开头的行都将被视为注释。也可以使用空行。

  • 任何其他行将被视为命令行参数以用作默认设置。每行指定一个设置。

实际命令行中如果有值,将会将对应的默认值覆盖

例如,假设您有以下mocha.opts文件:

# mocha.opts

  --require should
  --reporter dot
  --ui bdd

上面的设置将默认报告者reporter设为dot,需要should库,并用了bdd接口。

将命令行中,输入以下内容,将报告者更改为list,并启用Growl支持:

$ mocha --reporter list --growl

报告器reporter

mocha有各种类型的reporter,默认的是spec

SPEC

Alias: Spec, spec

mocha的默认报告器

spec报告器输出一个嵌套的分层视图,就像测试用例一样。

第三方reporter

mocha允许自定义报告器,例如

ide插件

vscode的插件:
Mocha sidebar

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