Chai.js斷言庫API中文文檔

基于chai.js官方API文檔翻譯。僅列出BDD風格的expect/should API。TDD風格的Assert API由于不打算使用,暫時不放,后續(xù)可能會更新。

BDD

expectshould是BDD風格的,二者使用相同的鏈式語言來組織斷言,但不同在于他們初始化斷言的方式:expect使用構(gòu)造函數(shù)來創(chuàng)建斷言對象實例,而should通過為Object.prototype新增方法來實現(xiàn)斷言(所以should不支持IE);expect直接指向chai.expect,而should則是chai.should()

個人比較建議使用expect,should不僅不兼容IE,在某些情況下還需要改變斷言方式來填坑。詳細的比較可以看看官網(wǎng)Assertion Styles,說的很清楚。

var chai = require('chai') ,
  expect = chai.expect ,
  should = chai.should()

語言鏈

下面的接口是單純作為語言鏈提供以期提高斷言的可讀性。除非被插件改寫否則它們一般不提供測試功能。

  • to
  • be
  • been
  • is
  • that
  • which
  • and
  • has
  • have
  • with
  • at
  • of
  • same

.not

對之后的斷言取反

expect(foo).to.not.equal('bar')
expect(goodFn).to.not.throw(Error)
expect({ foo: 'baz'}).to.have.property('foo')
  .and.not.equal('bar')

.deep

設(shè)置deep標記,然后使用equalproperty斷言。該標記可以讓其后的斷言不是比較對象本身,而是遞歸比較對象的鍵值對

expect(foo).to.deep.equal({ bar: 'baz'})
expect({ foo: { bar: { baz: 'quux'}}})
  .to.have.deep.property('foo.bar.baz', 'quux')

deep.property中的特殊符號可以使用雙反斜杠進行轉(zhuǎn)義(第一個反斜杠是在字符串參數(shù)中對第二個反斜杠進行轉(zhuǎn)義,第二個反斜杠用于在property中進行轉(zhuǎn)義)

var deepCss = { '.link': { '[target]': 42 } }
expect(deepCss).to.have.deep.property('\\.link.\\[target\\]', 42)

.any

keys斷言之前使用any標記(與all相反)

expect(foo).to.have.any.keys('bar', 'baz')

.all

keys斷言之前使用all標記(與any相反)

expect(foo).to.have.all.keys('bar', 'baz')

.a(type) / .an(type)

  • type:String,被測試的值的類型

aan斷言即可作為語言鏈又可作為斷言使用

// 類型斷言
expect('test').to.be.a('string');
expect({ foo: 'bar' }).to.be.an('object');
expect(null).to.be.a('null');
expect(undefined).to.be.an('undefined');
expect(new Error).to.be.an('error');
expect(new Promise).to.be.a('promise');
expect(new Float32Array()).to.be.a('float32array');
expect(Symbol()).to.be.a('symbol');

// es6 overrides
expect({[Symbol.toStringTag]:()=>'foo'}).to.be.a('foo');

// language chain
expect(foo).to.be.an.instanceof(Foo);

.include(value) / contains(value)

  • value:Object | String | Number

include()contains()即可作為屬性類斷言前綴語言鏈又可作為作為判斷數(shù)組、字符串是否包含某值的斷言使用。當作為語言鏈使用時,常用于key()斷言之前

expect([1, 2, 3]).to.include(2)
expect('foobar').to.include('bar')
expect({ foo: 'bar', hello: 'universe' }).to.include.keys('foo')

.ok

斷言目標為真值。

expect('everything').to.be.ok
expect(1).to.be.ok
expect(false).to.not.be.ok
expect(null).to.not.be.ok

.true

斷言目標為true,注意,這里與ok的區(qū)別是不進行類型轉(zhuǎn)換,只能為true才能通過斷言

expect(true).to.be.true
expect(1)to.not.be.true

.false

斷言目標為false

expect(false).to.be.false
expect(0).to.not.be.false

.null

斷言目標為null

expect(null).to.be.null
expect(undefined).to.not.be.null

.undefined

斷言目標為undefined

expect(undefine).to.be.undefined
expect(null).to.not.be.undefined

.NaN

斷言目標為非數(shù)字NaN

expect('foo').to.be.null
expect(4)to.not.be.null

.exist

斷言目標存在,即非null也非undefined

var foo = 'hi',
  bar = null,
  baz

expect(foo).to.exist
expect(bar).to.not.exist
expect(baz).to.not.exist

.empty

斷言目標的長度為0。對于數(shù)組和字符串,它檢查length屬性,對于對象,它檢查可枚舉屬性的數(shù)量

expect([]).to.be.empty
expect('').to.be.empty
expect({}).to.be.empty

.arguments

斷言目標是一個參數(shù)對象arguments

function test () {
  expect(arguments).to.be.arguments
}

.equal(value)

  • value:Mixed

斷言目標嚴格等于(===)value。另外,如果設(shè)置了deep標記,則斷言目標深度等于value

expect('hello').to.equal('hello')
expect(42).to.equal(42)
expect(1).to.not.equal(true)
expect({ foo: 'bar'}).to.not.equal({ foo: 'bar'})
expect({ foo: 'bar'}).to.deep.equal({foo: 'bar'})

.eql(value)

  • value:Mixed

斷言目標深度等于value,相當于deep.equal(value)的簡寫

expect({ foo: 'bar' }).to.eql({ foo: 'bar' })
expect([1, 2, 3]).to.eql([1, 2, 3])

.above(value)

  • value: Number

斷言目標大于(超過)value

expect(10).to.be.above(5)

也可接在length后來斷言一個最小的長度。相比直接提供長度的好處是提供了更詳細的錯誤消息

expect('foo').to.have.length.above(2)
expect([1, 2, 3]).to.have.length.above(2)

.least(value)

  • value: Number

斷言目標不小于(大于或等于)value

expect(10).to.be.at.least(10)

也可接在length后來斷言一個最小的長度。相比直接提供長度的好處是提供了更詳細的錯誤消息

expect('foo').to.have.length.of.at.least(3)
expect([1, 2, 3]).to.have.length.of.at.least(3)

.below(value)

  • value:Number

斷言目標小于value

expect(5).to.be.below(10)

也可接在length后來斷言一個最大的長度。相比直接提供長度的好處是提供了更詳細的錯誤消息

expect('foo').to.have.length.below(4)
expect([1, 2, 3]).to.have.length.below(4)

.most(value)

  • value:String

斷言目標不大于(小于或等于)value

expect(5).to.be.at.most(5)

也可接在length后來斷言一個最大的長度。相比直接提供長度的好處是提供了更詳細的錯誤消息

expect('foo').to.have.length.of.at.most(4)
expect([1, 2, 3]).to.have.length.of.at.most(3)

.within(start, finish)

  • start:Number,下限
  • finish:Number,上限

斷言目標在某個區(qū)間內(nèi)

expect(7).to.be.within(5, 10)

也可接在length后來斷言一個長度區(qū)間。相比直接提供長度的好處是提供了更詳細的錯誤消息

expect('foo').to.have.length.within(2, 4)
expect([1, 2, 3]).to.have.length.within(2, 4)

.instanceof(constructor)

  • constructor:Constructor,構(gòu)造函數(shù)

斷言目標是構(gòu)造函數(shù)constructor的一個實例

var Tea = function (name) { this.name = name },
  Chai = new Tea('chai')

expect(Chai).to.be.an.instanceof(Tea)
expect([1, 2, 3]).to.be.an.instanceof(Array)

.property(name, [value])

  • name:String,屬性名
  • value:Mixed,可選,屬性值

斷言目標是否擁有某個名為name的屬性,可選地如果提供了value則該屬性值還需要嚴格等于(===value。如果設(shè)置了deep標記,則可以使用點.和中括號[]來指向?qū)ο蠛蛿?shù)組中的深層屬性

// 簡單引用
var obj = { foo: 'bar' }
expect(obj).to.have.property('foo')
expect(pbj).to.have.property('foo', 'bar')

// 深層引用
var deepObj = {
  green: { tea: 'matcha' },
  teas: [ 'Chai', 'matcha', { tea: 'konacha' } ]
}

expect(deepObj).to.have.deep.property('green.tea', 'matcha')
expect(deepObj).to.have.deep.property('teas[1]', 'matcha')
expect(deepObj).to.have.deep.property('teas[2].tea', 'konacha')

如果目標是一個數(shù)組,還可以直接使用一個或多個數(shù)組下標作為name來在嵌套數(shù)組中斷言deep.property

var arr = [
  [ 'chai', 'matcha', 'konacha' ],
  [ { tea: 'chai' },
    { tea: 'matcha' },
    { tea: 'konacha' }
  ]
]

expect(arr).to.have.deep.property('[0][1]', 'matcha')
expect(arr).to.have.deep.property('[1][2].tea', 'konacha')

此外,property把斷言的主語(subject)從原來的對象變?yōu)楫斍皩傩缘闹担沟每梢栽谄浜筮M一步銜接其它鏈式斷言(來針對這個屬性值進行測試)

expect(obj).to.have.property('foo')
  .that.is.a('string')
expect(deepObj).to.have.property('green')
  .that.is.an('object')
  .that.deep.equals({ tea: 'matcha' })
expect(deepObj).to.have.property('teas')
  .that.is.an('array')
  .with.deep.property('[2]')
    .that.deep.equals({ tea: 'konacha' })

注意,只有當設(shè)置了deep標記的時候,在property() name中的點(.)和中括號([])才必須使用雙反斜杠\進行轉(zhuǎn)義(為什么是雙反斜杠,在前文有提及),當沒有設(shè)置deep標記的時候,是不能進行轉(zhuǎn)義的

// 簡單指向
var css = { '.link[target]': 42 }
expect(css).to.have.property('.link[target]', 42)

//深度指向
var deepCss = { 'link': { '[target]': 42 } }
expect(deepCss).to.have.deep.property('\\.link\\.[target]', 42)

.ownProperty(name)

  • name:String,屬性名
    斷言目標擁有名為name的自有屬性
expect('test').to.have.ownProperty('length')

.ownPropertyDescription(name[, descriptor])

  • name:String,屬性名
  • descriptor: Object,描述對象,可選

斷言目標的某個自有屬性存在描述符對象,如果給定了descroptor描述符對象,則該屬性的描述符對象必須與其相匹配

expect('test').to.have.ownPropertyDescriptor('length')
expect('test').to.have.ownPropertyDescriptor('length', {
  enumerable: false,
  configrable: false,
  writeable: false,
  value: 4
})
expect('test').not.to.have.ownPropertyDescriptor('length', {
  enumerable: false,
  configurable: false,
  writeable: false,
  value: 3  
})
// 將斷言的主語改為了屬性描述符對象
expect('test').to.have.ownPropertyDescriptor('length')
  .to.have.property('enumerable', false)
expect('test').to.have.ownPropertyDescriptor('length')
  .to.have.keys('value')

.length

設(shè)置.have.length標記作為比較length屬性值的前綴

expect('foo').to.have.length.above(2)
expect([1, 2, 3]).to.have.length.within(2, 4)

.lengthOf(value)

  • value:Number

斷言目標的length屬性為期望的值

expect([1, 2, 3]).to.have.lengthOf(3)
expect('foobar').to.have.lengthOf(6)

.match(regexp)

  • regexp:RegExp,正則表達式

斷言目標匹配到一個正則表達式

expect('foobar').to.match(/^foo/)

.string(string)

  • string:String,字符串

斷言目標字符串包含另一個字符串

expect('foobar').to.have.string('bar')

.keys(key1, [key2], [...])

  • key:String | Array | Object 屬性名

斷言目標包含傳入的屬性名。與anyallcontains或者have前綴結(jié)合使用會影響測試結(jié)果:

當與any結(jié)合使用時,無論是使用have還是使用contains前綴,目標必須至少存在一個傳入的屬性名才能通過測試。注意,any或者all應(yīng)當至少使用一個,否則默認為all

當結(jié)合allcontains使用時,目標對象必須至少擁有全部傳入的屬性名,但是它也可以擁有其它屬性名

當結(jié)合allhave使用時,目標對象必須且僅能擁有全部傳入的屬性名

// 結(jié)合any使用
expect({ foo: 1, bar: 2, baz: 3 }).to.have.any.keys('foo', 'bar')
expect({ foo: 1, bar: 2, baz: 3 }).to.contains.any.keys('foo', 'bar')

// 結(jié)合all使用
expect({ foo: 1, bar: 2, baz: 3 }).to.have.all.keys('foo', 'bar', 'baz')
expect({ foo: 1, bar: 2, baz: 3 }).to.contains.all.keys('foo', 'bar')

// 傳入string
expect({ foo: 1, bar: 2, baz: 3 }).to.have.any.keys('foo')
// 傳入Array
expect({ foo: 1, bar: 2, baz: 3 }).to.have.all.keys(['foo', 'bar', 'baz'])
// 傳入Object
expect({ foo: 1, bar: 2, baz: 3 }).to.have.any.keys({ bar: 2, foo: 1 })

.throw(constructor)

  • constructor: ErrorConstroctor | String | RegExp

斷言目標函數(shù)會拋出一個指定錯誤或錯誤類型(使用instanceOf計算),也可使用正則表達式或者字符串來檢測錯誤消息

var err = new RefernceError('this is a bad function')
var fn = function () { throw err }

expect(fn).to.throw(ReferenceError)
expect(fn).to.throw(Error)
expect(fn).to.throw(/bad function/)
expect(fn).to.not.throw('good function')
expect(fn).to.throw(ReferrenceError, /bad function/)
expect(fn).to.throw(err)

注意,當一個拋錯斷言被否定了(前面有.not),那么它會從Error構(gòu)造函數(shù)開始依次檢查各個可能傳入的參數(shù)。檢查一個只是消息類型不匹配但是已知的錯誤,合理的方式是先斷言該錯誤存在,然后使用.and后斷言錯誤消息不匹配

expect(fn).to.throw(ReferenceError)
  .and.not.throw(/good function/)

.respondTo(method)

  • method:String

斷言目標類或?qū)ο髸憫?yīng)一個方法(存在這個方法)

Klass.prototype.bar = function () {}
expect(Klass).to.respondTo('bar')
expect(obj).to.respondTo('bar')

如果需要檢查一個構(gòu)造函數(shù)是否會響應(yīng)一個靜態(tài)方法(掛載在構(gòu)造函數(shù)本身的方法),請查看itself標記

Klass.baz = function () {}
expect(Klass).itself.to.respondTo('baz')

.itself

設(shè)置itself標記,然后使用respondTo斷言

function Foo () {}
Foo.bar = function () {}
Foo.prototype.baz = function () {}

expect(Foo).itself.to.respondTo('bar')
expect(Foo).itself.not.to.respond('baz')

.satisfy(method)

  • method:Function,測試器,接受一個參數(shù)表示目標值,返回一個布爾值

斷言目標值能夠讓給定的測試器返回真值

expect(1).to.satisfy(function (num) { return num > 0 })

.closeTo(expected, delta)

  • expect:Numbre,期望值
  • delta:Numbre,范圍半徑

斷言目標數(shù)字等于expected,或在期望值的+/-delta范圍內(nèi)

expect(1.5).to.be.closeTo(1, 0.5)

.members(set)

  • set:Array

斷言目標是set的超集,或前者有后者所有嚴格相等(===)的成員。另外,如果設(shè)置了deep標記,則成員進行深度比較(include/contains只能接受單個值,但它們的主語除了是數(shù)組,還可以判斷字符串;members則將它們的能力擴展為能夠接受一個數(shù)組,但主語只能是數(shù)組)

expect([1, 2, 3]).to.include.members([3, 2])
expect([1, 2, 3]).to.not.include.members([3, 2, 8])

expect([4, 2]).to.have.members([2, 4])
expect([5, 2]).to.not.have.members([5, 2, 1])

expect([{ id: 1 }]).to.deep.include.members([{ id: 1 }])

.oneOf(list)

  • list:Array

斷言目標值出現(xiàn)在list數(shù)組的某個頂層位置(直接子元素,嚴格相等)

expect('a').to.be.oneOf(['a', 'b', 'c'])
expect(9).to.not.be.oneOf(['z'])

// 嚴格相等,所以對象類的值必須為同一個引用才能被判定為相等
var three = [3]
expect([3]).to.not.be.oneOf([1, 2, [3]])
expect(three).to.not.be.oneOf([1, 2, [3]])
expect(three).to.be.oneOf([1, 2, three])

change(object, property)

  • object:Object,對象
  • property:String,屬性名

斷言目標方法會改變指定對象的指定屬性

var obj = { val: 10 }
var fn = function () { obj.val += 3 }
var noChangeFn = function () { return 'bar' + 'baz' }

expect(fn).to.change(obj, 'val')

.increase(object, property)

  • object:Object,對象
  • property:String,屬性名

斷言目標方法會增加指定對象的屬性

var obj = { val: 10 }
var fn = function () { obj.val = 15 }
expect(fn).to.increase(obj, val)

.decrease(object, property)

  • object:Object,對象
  • property:String,屬性名

斷言目標方法會減少指定對象的屬性

var obj = { val: 10 }
var fn = function () { obj.val = 5 }
expect(fn).to.decrease(obj, val)

.extensible

斷言目標對象是可擴展的(可以添加新的屬性)

var nonExtensibleObject = Object.preventExtensions({})
var sealedObject = Object.seal({})
var frozenObject = Object.freeze({})

expect({}).to.be.extensible
expect(nonExtensibleObject).to.not.be.extensible
expect(sealObject).to.not.be.extensible
expect(frozenObject).to.not.be.extensible

.sealed

斷言目標對象是封閉的(無法添加新的屬性并且存在的屬性不能被刪除但可以被修改)

var sealedObject= Object.seal({})
var frozenObject = Object.freeze({})

expect(sealedObject).to.be.sealed
expect(frozenObject).to.be.sealed
expect({}).to.not.be.sealed

.frozen

斷言目標對象是凍結(jié)的(無法添加新的屬性并且存在的屬性不能被刪除和修改)

var frozenObject = Object.freeze({})

expect(frozenObject).to.be.frozen
expect({}).to.not.be.frozen

TDD

除了一些語法糖以外,Chai提供的assert風格的斷言和node.js包含的assert模塊非常相似。assert風格是三種斷言風格中唯一不支持鏈式調(diào)用的。
// TODO API 參考

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 134,993評論 19 139
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法,類相關(guān)的語法,內(nèi)部類的語法,繼承相關(guān)的語法,異常的語法,線程的語...
    子非魚_t_閱讀 31,779評論 18 399
  • { "Unterminated string literal.": "未終止的字符串文本。", "Identifi...
    一粒沙隨風飄搖閱讀 10,786評論 0 3
  • 1.調(diào)脾胃 脾胃是氣血生化之源,《靈樞.決氣》中有“中焦受氣取汁,變化而赤,謂之血”之說,所以治療血癥,必須重視調(diào)...
    bear家的馴鹿大人閱讀 369評論 0 0
  • HTML規(guī)范 - 整體結(jié)構(gòu) HTML基礎(chǔ)設(shè)施 文件應(yīng)以“<!DOCTYPE ......>”首行頂格開始,推薦使用...
    小豌豆書吧閱讀 407評論 0 0