ㅤㅤㅤ
ㅤㅤㅤ
ㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤ(不應當急於求成,應當去熟悉自己的研究對象,鍥而不捨,時間會成全一切。凡事開始最難,然而更難的是何以善終。——莎士比亞)
ㅤㅤㅤ
ㅤㅤㅤ
ㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤ
什麼是單元測試
指對軟件中的最小可測試單元進行檢查和驗證。對於單元測試中單元的含義,一般來說,要根據實際情況去判定其具體含義,如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;
});
});