ㅤㅤㅤ
ㅤㅤㅤ
ㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤ(不应当急于求成,应当去熟悉自己的研究对象,锲而不舍,时间会成全一切。凡事开始最难,然而更难的是何以善终。——莎士比亚)
ㅤㅤㅤ
ㅤㅤㅤ
ㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤ
什么是单元测试
指对软件中的最小可测试单元进行检查和验证。对於单元测试中单元的含义,一般来说,要根据实际情况去判定其具体含义,如C语言中单元指一个函数,Java里单元指一个类,图形化的软件中可以指一个窗口或一个菜单等。总的来说,单元就是人为规定的最小的被测功能模块。单元测试是在软件开发过程中要进行的最低级别的测试活动,软件的独立单元将在与程序的其他部分相隔离的情况下进行测试
为什么需要单元测试
- 保障软件项目质量,减少企业损失
没有经过测试的代码犹如在战场上裸奔的士兵。人不是机器,即便是测试人员,也不能保证每个功能是否完全稳定,因为只有先让开发者先去消费它,才能给予最重要的质量保证
- 减少企业测试成本,避免投入冗余的测试资源
高质量的单元测试远远比人工测试更高效。在’全自动化’,'人工智能’的大时代,机器远远比人工更高效,与其投入大量的测试资源,比如花时间编写高效稳定的单元测试
- 更精准的定位程序中的bug
测试基于表面去判断问题,而只有开发是知其所以然的。毕竟代码是开发者编写的,测试人员的优势只在于时间和对功能的熟悉度,若有了单元测试,不仅能节省测试人员的时间,还能够减少程序bug数量
- 避免开发者对测试人员产生依赖,完全不关心其代码的测试
人都是有惰性的,因为 测试人员的存在,导致开发者对自己编写的代码质量漠不关心。对测试人员过度依赖的项目必定是不稳定和不安全的
- 更高的可维护性
由于缺少单元测试,程序中存在着’坏代码’。一些’千年老bug’,'临时拆东墙补西墙的解决方案’使得代码的维护和重构难度愈来愈大,牵一发而动全身。通过单元测试尽可能的提高代码覆盖率
- 了解你的代码性能
虽然这不是单元测试的主要目的,但在单元测试中编写运行指定场景的性能分析会非常容易,在现有的代码测试中快速复制一份能让指定对象运行起来的测试代码,运行它测量性能,修改代码查看性能的变化情况,像德芙一样丝滑
- 证明你的工作已完成
无论需求驱动还是测试驱动,你的任务通常都是完成一系列代码,实现具体的一系列功能。那么当你提交代码时,你怎么证明你的提交时这个功能中的未完成部分还是已经全部完成,如何证明你功能是否经过测试可以随时合并到生产环境,换句话说,你怎么证明你的代码完全按照实现的“约定行为”运行的。
当我们仅使用口头或者书面形式描述“约定行为”时,非常困难的一点是如何消除自然语言中的歧义,如何避免不同的人们基于各自不同背景知识脑补出不同的内容导致隐形的分歧。而使用代码来描述行为规约的一个好处就是计算机运行需要指定的指令,不会存在二义性。因此用一段运行的代码可以完整无误的证明你的代码是完成的
单元测试原则
- 单一职责
如果一段代码承担的职责越多,为其编写单元的时候就要构建更多的输入数据,然后推测它的输入。比如,一段代码中既包含数据库的链接,也包含查询,那么为它编写测试用例就要同事关注数据库连接和数据库查询。较好的方式是将这两种职责进行解耦分离,变成两个单一职责的方法,分别测试数据库连接和数据库查询
- 接口抽象
通过对程序代码进行接口抽象后,我们可以针对接口进行测试,而具体代码实现的变化不影响为接口编写的单元测试
- 层次分离
层次分离实际上是单一职责的一种实现。在MVC结构的应用中,就是典型的层次分离模型,如果不分离各个层次,无法想象这个代码该如何切入测试。通过分层之后,可以逐层测试,逐层保证
对于开发者来说,不仅要编写单元测试,还应当编写可测试代码
单元测试模式
- TDD 测试驱动开发(Test-Driven Development)
测试驱动开发是敏捷开发中的一项核心实践和技术,也是一种设计方法论。TDD的原理是在开发功能代码之前,先编写单元测试用例代码,测试代码确定需要编写什么产品代码。TDD的基本思路就是通过测试来推动整个开发的进行,但测试驱动开发并不只是单纯的测试工作,而是把需求分析,设计,质量控制量化的过程。TDD首先考虑使用需求(对象、功能、过程、接口等),主要是编写测试用例框架对功能的过程和接口进行设计,而测试框架可以持续进行验证
- BDD 行为驱动开发(Behavior Driven Development)
行为驱动开发是一种敏捷软件开发的技术,它鼓励软件项目中的开发者、QA和非技术人员或商业参与者之间的协作。主要是从用户的需求出发,强调系统行为。BDD最初是由Dan North在2003年命名,它包括验收测试和客户测试驱动等的极限编程的实践,作为对测试驱动开发的回应。
在接下来的演示中,我们均采用BDD模式
BDD是一种敏捷软件开发的技术。它对TDD的理念进行了扩展,在TDD中侧重点偏向开发,通过测试用例来规范约束开发者编写出质量更高、bug更少的代码。而BDD更加侧重设计,其要求在设计测试用例的时候对系统进行定义,倡导使用通用的语言将系统的行为描述出来,将系统设计和测试用例结合起来,从而以此为驱动进行开发工作。
BDD的通用语言是一种近乎自然语言的描述软件的形式。传统的开发模式中,客户很难从技术层面理解问题,开发人员很难从业务需求考虑问题,基于这种通用语言形式可以尽可能的避免客户和开发者在沟通上的障碍,实现客户和开发者同时定义系统的需求。避免了因为理解需求不充分而带来的不必必要的工作量。
Nodejs断言库
- assert
node中绝大多数单元测试的基础,它可以测试一个条件,如果条件未满足,则抛出错误,很多第三方框架都用了assert模块,但缺点是,一旦检查失败,将会抛出异常停止整个应用,这对于大规模断言检查时,并不友好,因为更通用的做法是,记录抛出的异常,并继续执行,生成测试报告
特性
- 简单
- 轻量
- 原生
var assert = require('assert');
function add (a, b) {
return a + b;
}
var expect = add(1, 2);
assert(expect === 3, 'should return 3');
- should.js
它类似BDD的风格表示断言,让测试更容易看懂,它的设计之初就是搭配其他测试框架一起使用。
使用上也非常容易,因为它只是给Object.protptype增加了一个should属性,我们可以用它写出表达能力更强的断言
特性
- 更强的语义化
- 不依赖框架
- 基于assert的扩展,轻量,简单
var should = require('should');
var user = {
name: 'tj'
, pets: ['tobi', 'loki', 'jane', 'bandit']
};
user.should.have.property('name', 'tj');
user.should.have.property('pets').with.lengthOf(4);
// If the object was created with Object.create(null)
// then it doesn't inherit `Object.prototype`, so it will not have `.should` getter
// so you can do:
should(user).have.property('name', 'tj');
// also you can test in that way for null's
should(null).not.be.ok();
someAsyncTask(foo, function(err, result){
should.not.exist(err);
should.exist(result);
result.bar.should.equal(foo);
});
- chai
当前JavaScript流行的断言库,内置了should,expect,assert,同样的,也是配合框架使用,在接下来的演示中,均采用此断言库演示
特性
- 内置了should,expect,assert
- 插件机制
- 更灵活更语义化的断言
var expect = require('chai').expect
, foo = 'bar'
, beverages = { tea: [ 'chai', 'matcha', 'oolong' ] };
expect(foo).to.be.a('string');
expect(foo).to.equal('bar');
expect(foo).to.have.lengthOf(3);
expect(beverages).to.have.property('tea').with.lengthOf(3);
NodejS测试框架
- mocha
相对比较新,运行在node.js上的JavaScript测试框架,可以用来做 TDD(Test-Driven Development)或 BDD(Behavior Driven Development)风格的测试,在接下来的演示中,均采用此框架进行演示
特性
- 全局变量泄露测试
Mocha 能够发现那种不小心创建出来的全局变量泄露,如果创建了全局变量,它会在测试时抛出错误。如果想禁用全局泄露检查,可以运行 mocha 命令时加上 --ignored-leaks 选项- 用 Mocha挂钩定义设置和清理逻辑
BDD 接口 beforeEach()、afterEach()、before()和 after()接受回调,可以用来定义设置和清理逻辑。- 测试异步逻辑
给定义测试逻辑函数添加一个参数,就可以把 Mocha 测试用例定义为异步的。这个参数通常被命名为done。
var assert = require('assert');
describe('Array', function() {
describe('#indexOf()', function() {
it('should return -1 when the value is not present', function() {
assert.equal([1, 2, 3].indexOf(4), -1);
});
});
});
- vows
一个结构化更强的,且更容易理解的和维护的测试框架,拥有自己的BDD术语定义,和mocha的不同主要体现在风格和并行性上
特性
- 一个测试套件中包含一个或多个批次
- 批次和上下文是并行运行的。上下文中可能包含主题、一个或多个誓约,以及/或者一或多个先关联的情境(内部情况也是并行运行的)
- 主题是跟情境相关的测试逻辑。誓约是对主题结果的测试
var vows = require('vows'),
assert = require('assert');
vows.describe('Deep Thought').addBatch({
'An instance of DeepThought': {
topic: new DeepThought,
'should know the answer to the ultimate question of life': function (deepThought) {
assert.equal (deepThought.question('what is the answer to the universe?'), 42);
}
}
});
ㅤㅤㅤ
ㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤ
ㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤ
ㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤ
有趣 简单 灵活
mocha是一个功能丰富的JavaScript测试框架,可在Node.js和浏览器中运行,从而使异步测试变得简单而有趣。Mocha测试按顺序运行,从而可以灵活,准确地报告,同时将未捕获的异常映射到正确的测试用例
https://github.com/mochajs/mocha/blob/master/example/config/.mocharc.js
我当前mocha的版本是7.1.2,chai的版本是4.2.0
- 安装
npm install --global mocha
或者npm install --save-dev mocha
- 入门
编写test.js文件
const assert = require('assert');
describe('Array', function() {
describe('#indexOf()', function() {
it('should return -1 when the value is not present', function() {
assert.equal([1, 2, 3].indexOf(4), -1);
});
});
});
- describe 代表着一组测试,第一个参数是该测试套件的名称,第二个参数是执行函数,且测试用例可以进行嵌套,更方便的进行分层级的测试
- it 代表一个测试用例,是测试脚本的最小单元,第一个参数是该测试用例的名称,第二个参数是执行函数
- context describe的别名,作用相同,一个更语义化的名称,在接下来的演示中,均采用此名称作为测试套件名称
- specify it的别名,和context同理
执行命令mocha test.js得到结果
$ mocha test.js
Array
#indexOf()
✓ should return -1 when the value is not present
1 passing (9ms)
mocha内置了assert断言库,但如果抛出异常,则会停止程序执行,建议使用其他断言库,在这里我们选择搭配chai
下面总结了一些mocha的常用API
- mocha默认BDD接口,所以提供了以下四种生命周期函数
- before
在所有测试用例执行前执行
- beforeEach
在每一个测试用例执行前执行
- after
在所有测试用例执行结束后执行
- afterEach
在每一个测试用例结束后执行
import { expect } from 'chai';
context('test sum demo', () => {
before(() => {
console.log('所有测试用例执行前执行');
});
beforeEach(() => {
console.info('每一个测试用例执行前执行');
});
afterEach(() => {
console.info('每一个测试用例执行后运行');
});
after(() => {
console.info(`所有测试用例执行后执行`);
});
specify('test mocha life cycle', () => {
expect(3).to.be.eq(3);
});
specify('test mocha life cycle2', () => {
expect(3).to.be.eq(3);
});
});
typescript test mocha
test sum demo
所有测试用例执行前执行
每一个测试用例执行前执行
✓ test mocha life cycle
每一个测试用例执行后运行
每一个测试用例执行前执行
✓ test mocha life cycle2
每一个测试用例执行后运行
所有测试用例执行后执行
2 passing (19ms)
- 支持async/await
context('test async/await context', () => {
specify('await', async () => {
const data = new Promise((resolve) => {
setTimeout(() => {
resolve('延迟一秒');
}, 1000);
});
console.info(await data);
});
});
typescript test mocha
test async/await context
延迟一秒
✓ await (1008ms)
1 passing (1s)
- 运行指定的测试套件或测试用例
使用only关键字,可以运行指定的测试条件,下面的代码中,由于给’test async/await context’使用了only,所以只会执行该测试套件
context('test sum demo', () => {
before(() => {
console.log('所有测试用例执行前执行');
});
beforeEach(() => {
console.info('每一个测试用例执行前执行');
});
afterEach(() => {
console.info('每一个测试用例执行后运行');
});
after(() => {
console.info(`所有测试用例执行后执行`);
});
specify('test mocha life cycle', () => {
expect(3).to.be.eq(3);
});
specify('test mocha life cycle2', () => {
expect(3).to.be.eq(3);
});
});
context.only('test async/await context', () => {
specify('await', async () => {
const data = new Promise((resolve) => {
setTimeout(() => {
resolve('延迟一秒');
}, 1000);
});
console.info(await data);
});
});
typescript test mocha
test async/await context
延迟一秒
✓ await (1006ms)
1 passing (1s)
- 也可以选择执行多个指定的测试套件
context('test sum demo', () => {
before(() => {
console.log('所有测试用例执行前执行');
});
beforeEach(() => {
console.info('每一个测试用例执行前执行');
});
afterEach(() => {
console.info('每一个测试用例执行后运行');
});
after(() => {
console.info(`所有测试用例执行后执行`);
});
specify('test mocha life cycle', () => {
expect(3).to.be.eq(3);
});
specify('test mocha life cycle2', () => {
expect(3).to.be.eq(3);
});
});
context.only('test async/await context', () => {
specify('await', async () => {
const data = new Promise((resolve) => {
setTimeout(() => {
resolve('延迟一秒');
}, 1000);
});
console.info(await data);
});
});
context.only('test async/await context two', () => {
specify('await', async () => {
const data = new Promise((resolve) => {
setTimeout(() => {
resolve('延迟二秒');
}, 2000);
});
console.info(await data);
});
});
typescript test mocha
test async/await context
延迟一秒
✓ await (1005ms)
test async/await context two
延迟二秒
✓ await (2006ms)
2 passing (3s)
- 在嵌套的测试套件中使用only
context.only('test async/await context', () => {
specify('await', async () => {
const data = new Promise((resolve) => {
setTimeout(() => {
resolve('延迟一秒');
}, 1000);
});
console.info(await data);
});
specify.only('await only', async () => {
const data = new Promise((resolve) => {
setTimeout(() => {
resolve('only');
}, 1000);
});
console.info(await data);
});
});
typescript test mocha
test async/await context
only
✓ await only (1006ms)
1 passing (1s)
- 跳出指定的测试套件或测试用例,被跳出的会被标记
使用skip关键字,可以跳过指定的测试套件或测试用例,被跳出的会被标记
context('test sum demo', () => {
before(() => {
console.log('所有测试用例执行前执行');
});
beforeEach(() => {
console.info('每一个测试用例执行前执行');
});
afterEach(() => {
console.info('每一个测试用例执行后运行');
});
after(() => {
console.info(`所有测试用例执行后执行`);
});
specify('test mocha life cycle', () => {
console.info('我存在');
expect(3).to.be.eq(3);
});
specify.skip('test mocha life cycle2', () => {
console.info('我被跳过');
expect(3).to.be.eq(3);
});
});
context.skip('test async/await context', () => {
specify('await', async () => {
const data = new Promise((resolve) => {
setTimeout(() => {
resolve('延迟一秒');
}, 1000);
});
console.info(await data);
});
specify('await only', async () => {
const data = new Promise((resolve) => {
setTimeout(() => {
resolve('我先执行');
}, 1000);
});
console.info(await data);
});
前缀为 '-'的是被跳过的标记
typescript test mocha
test sum demo
所有测试用例执行前执行
每一个测试用例执行前执行
我存在
✓ test mocha life cycle
每一个测试用例执行后运行
- test mocha life cycle2
所有测试用例执行后执行
test async/await context
- await
- await only
1 passing (32ms)
3 pending
- 对执行失败的测试进行额外的重新测试
使用this.retries可以设置重试次数
context('text retries demo', function () {
let sum = 0;
specify('should retries 3', function () {
sum += 1;
this.retries(3);
console.info(`重试次数${sum}`);
throw new Error('throw error');
})
});
typescript test mocha
text retries demo
重试次数1
重试次数2
重试次数3
重试次数4
1) should retries 3
0 passing (39ms)
1 failing
1) typescript test mocha
text retries demo
should retries 3:
Error: throw error
at Context.<anonymous> (study-node-modul-ts/mocha.ts:42:13)
- 参数化的动态测试生成
利用逻辑代码,生成动态的测试用例
function add() {
return Array.prototype.slice.call(arguments).reduce(function (prev: any, curr: any) {
return prev + curr;
}, 0);
}
context('add()', function () {
const chunk = [
{ args: [1, 2], expected: 3 },
{ args: [1, 2, 3], expected: 6 },
{ args: [1, 2, 3, 4], expected: 10 }
];
chunk.forEach(function (test) {
specify('correctly adds ' + test.args.length + ' args', function () {
expect(add.apply(null, test.args)).to.be.eq(test.expected);
});
});
});
add()
✓ correctly adds 2 args
✓ correctly adds 3 args
✓ correctly adds 4 args
3 passing (24ms)
- 自定义测试时间阶段
context('test slow demo', function () {
specify('should fast', function () {
this.slow(1000);
});
specify('should normal', async function () {
this.slow(1000);
await new Promise(resolve => {
setTimeout(() => {
resolve('----');
},1500);
});
});
specify('should slow', async function () {
this.slow(1500);
await new Promise(resolve => {
setTimeout(() => {
resolve('----');
}, 2000);
});
});
});
test slow demo
✓ should fast
✓ should normal (1504ms)
✓ should slow (2003ms)
3 passing (4s)
- 测试套件超时设置
context('test time out', function () {
specify('should overtime', function (done) {
this.timeout(50);
setTimeout(done, 100);
});
specify('no should overtime', function (done) {
setTimeout(done, 20);
});
});
test time out
✓ should overtime (103ms)
✓ no should overtime
2 passing (142ms)
- 测试用例超时设置
context('test time out 50ms', function () {
this.timeout(50);
specify('should overtime', function (done) {
setTimeout(done, 100);
});
specify('no should overtime', function (done) {
setTimeout(done, 20);
});
});
context('test time out 50ms', function () {
this.timeout(50);
specify('should overtime', function (done) {
setTimeout(done, 20);
});
specify('no should overtime', function (done) {
setTimeout(done, 20);
});
});
test time out 50ms
✓ should overtime (101ms)
✓ no should overtime
test time out 50ms
✓ should overtime
✓ no should overtime
4 passing (190ms)
mocha终端风格
在接下来的测试中,我们均使用以下测试代码
const { expect } = require('chai');
const fun = (data)=>{
return data;
};
context('test tty style', function () {
before('before', function () {
console.info('before');
});
after('after', function () {
console.info('after');
})
specify('should return 3', function () {
expect(fun(3)).to.be.eq(3);
});
specify('should return 2', function () {
expect(fun(3)).to.be.eq(2);
});
});
- –reporter spec
默认的测试报告风格
- –reporter dot matrix
dot matrix视图报告使用一系列的字符来表示报告的结果,失败的测试使用红色的!来表示,pending测试使用蓝色的,来表示。慢的测试用黄色的.来表示。这个终端输出的内容最少
我的ubuntu没有安装matrix样式,这里就借用官方的图
- –reporter nyan
有趣的动画风格
- –reporter TAP
https://en.wikipedia.org/wiki/Test_Anything_Protocol
- –reporter landing strip
landing strip飞机降落的跑道,测试报告就是像一架飞机轨道一样的视图
- –reporter list
当测试用例通过或失败时,列表报告器将输出一个简单的规格列表,并在输出的底部输出失败的详细信息
- –reporter progress
进度报告器实现了一个简单的进度栏
- –reporter json
测试完成(是否失败)后,JSON报告程序将输出一个大的JSON对象
- –reporter json-stream
输出的也是一个json,不同测试用例以换行符进行分割
- –reporter min --watch
这个报告只显示测试的整体情况,但是仍然会输出错误和失败的情况。和**–watch**选项结合使用最好,可视化更高一些?
- –reporter doc
生成一个包含html的body内容的测试报告
我们将它让如完整的html进行展示
- –reporter markdown
生成markdown格式的报告
在vscode中展示如下
- –reporter html
只有在浏览器中使用Mocha的时候才能生成这种报告
…等等还有很多展示风格,具体的大家可以查看官网
mocha启动配置
.opts格式的文件在未来版本中会被弃用,官方目前支持的格式有
- .js
- .yml
- jsonc
- package.json
更多格式可以在mocha官方的github上查看,在这里我们使用官方提供的.js配置为例
'use strict';
module.exports = {
diff: true, //抛错时展示差异
extension: ['js'], //需要加载的文件扩展名
package: './package.json', //package.json路径
reporter: 'nyan', //测试报告风格
slow: 75, //慢速阀值,超出会警告
timeout: 2000, //超时时间,超出警告
ui: 'bdd', //测试风格
'watch-files': ['lib/**/*.js', 'test/**/*.js'], //执行测试的路径
'watch-ignore': ["node_modules", ".git"] //指定忽略文件
};
使用 --config命令指定配置文件路径
chai断言API
const { expect } = require('chai');
- .not
断言否定
context('test mocha not', function () {
specify('should pass ', function () {
expect(function () { }).to.not.throw();
});
specify('should fail', function () {
expect({ a: 1 }).to.not.have.property('a');
});
specify('should pass', function () {
expect([1, 2]).to.be.an('array').that.does.not.include(3);
});
});
- .nested
在链中的所有以及断言中启用点和括号符号。.property.include
context('test mocha nested', function () {
specify('should pass ', function () {
expect({ a: { b: ['x', 'y'] } }).to.have.nested.property('a.b[1]');
});
specify('should pass', function () {
expect({ a: { b: ['x', 'y'] } }).to.nested.include({ 'a.b[1]': 'y' });
});
specify('should fail', function () {
expect({ a: { b: ['x', 'y'] } }).to.have.nested.property('a.b[2]');
});
});
- own
使链中的所有和断言忽略继承和原型上的属性。.property.include
context('test mocha nested', function () {
Object.prototype.b = 2;
specify('should pass ', function () {
expect({ a: 1 }).to.have.own.property('a');
});
specify('should pass', function () {
expect({ a: 1 }).to.have.own.property('b');
});
specify('should fail', function () {
expect({ a: 1 }).to.not.have.own.property('b');
});
});
- .ordered
断言成员排序
context('test mocha ordered', function () {
specify('should pass ', function () {
expect([1, 2]).to.have.ordered.members([1, 2])
.but.not.have.ordered.members([2, 1]);
});
specify('should pass', function () {
expect([1, 2, 3]).to.include.ordered.members([1, 2])
.but.not.include.ordered.members([2, 3])
});
specify('should fail', function () {
expect([1, 2]).to.have.ordered.members([2, 3])
.but.not.have.ordered.members([1, 2]);
});
});
- .any
兼容任何类型
- .all
所有类型
context('test mocha ordered', function () {
specify('should pass ', function () {
expect({ a: 1, b: 2 }).to.not.have.any.keys('a', 'd');
});
specify('should pass', function () {
expect({ a: 1, b: 2 }).to.not.have.all.keys('a', 'b');
});
specify('should fail', function () {
expect({ a: 1, b: 2 }).to.have.all.keys('a', 'b');
});
});
- .a
判断数据类型
context('test mocha .a', function () {
specify('should return pass ', function () {
expect('foo').to.be.a('string');
});
specify('should return pass', function () {
expect({ a: 1 }).to.be.an('object');
});
specify('should return pass', function () {
expect(null).to.be.a('null');
});
specify('should return pass ', function () {
expect(undefined).to.be.an('undefined');
});
specify('should return pass', function () {
expect(new Error).to.be.an('error');
});
specify('should return pass', function () {
expect(Promise.resolve()).to.be.a('promise');
});
specify('should return fail', function () {
expect(1).to.be.a('promise');
});
});
.a的复杂断言
context('test mocha .a', function () {
specify('should return pass ', function () {
expect([1, 2, 3]).to.be.an('array').that.includes(2);
});
specify('should return pass', function () {
expect([]).to.be.an('array').that.not.empty;
});
specify('should return pass', function () {
expect([]).to.be.an('array').that.is.empty;
});
specify('should return pass', function () {
expect({ b: 2 }).to.have.a.property('b');
});
});
- .include
断言是否包含
context('test mocha .include', function () {
specify('should return pass ', function () {
expect('foobar').to.include('foo');
});
specify('should return pass', function () {
expect([1, 2, 3]).to.include(2);
});
specify('should return pass', function () {
expect({ a: 1, b: 2, c: 3 }).to.include({ a: 1, b: 2 });
});
specify('should return pass', function () {
expect(new Set([1, 2])).to.include(2);
});
specify('should return pass', function () {
expect(new Map([['a', 1], ['b', 2]])).to.include(2);
});
specify('should return pass', function () {
expect([1, 2, 3]).to.be.an('array').that.includes(2);
});
specify('should return pass', function () {
expect({ a: { b: ['x', 'y'] } }).to.nested.include({ 'a.b[1]': 'y2' });
});
});
- .ok
断言是否为真
context('test mocha .ok', function () {
specify('should return pass ', function () {
expect(1).to.be.ok;
});
specify('should return pass', function () {
expect(true).to.be.ok
});
specify('should return pass', function () {
expect(0).to.not.be.ok;
});
specify('should return pass', function () {
expect(false).to.not.be.ok;
});
specify('should return pass', function () {
expect(null).to.not.be.ok;
});
specify('should return pass', function () {
expect(undefined).to.not.be.ok;
});
specify('should return pass', function () {
expect(false, 'this error').to.be.ok
});
});
- .true
断言是否为真(严格类型,类似JS的===)
context('test mocha .true', function () {
specify('should return pass ', function () {
expect(true).to.be.true;
});
specify('should return pass', function () {
expect(false).to.not.be.true;
});
specify('should return pass', function () {
expect(1).to.not.be.true;
});
specify('should return pass', function () {
expect(0, 'nooo why fail??').to.be.true;
});
});