Chai js斷言庫API中文文檔

基於chai.js官方API文檔翻譯。僅列出BDD風格的expect/should API。TDD風格的Assert API因爲不打算使用,暫時不放,後續可能會更新。javascript

BDD

expectshould是BDD風格的,兩者使用相同的鏈式語言來組織斷言,但不一樣在於他們初始化斷言的方式:expect使用構造函數來建立斷言對象實例,而should經過爲Object.prototype新增方法來實現斷言(因此should不支持IE);expect直接指向chai.expect,而should則是chai.should()css

我的比較建議使用expect,should不只不兼容IE,在某些狀況下還須要改變斷言方式來填坑。詳細的比較能夠看看官網Assertion Styles,說的很清楚。java

var chai = require('chai') ,
  expect = chai.expect ,
  should = chai.should()
複製代碼

語言鏈

下面的接口是單純做爲語言鏈提供以期提升斷言的可讀性。除非被插件改寫不然它們通常不提供測試功能。node

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

.not

對以後的斷言取反es6

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

.deep

設置deep標記,而後使用equalproperty斷言。該標記可讓其後的斷言不是比較對象自己,而是遞歸比較對象的鍵值對正則表達式

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

deep.property中的特殊符號可使用雙反斜槓進行轉義(第一個反斜槓是在字符串參數中對第二個反斜槓進行轉義,第二個反斜槓用於在property中進行轉義)數組

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

.any

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

expect(foo).to.have.any.keys('bar', 'baz')
複製代碼

.all

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

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()便可做爲屬性類斷言前綴語言鏈又可做爲做爲判斷數組、字符串是否包含某值的斷言使用。看成爲語言鏈使用時,經常使用於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的區別是不進行類型轉換,只能爲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

斷言目標爲非數字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。對於數組和字符串,它檢查length屬性,對於對象,它檢查可枚舉屬性的數量

expect([]).to.be.empty
expect('').to.be.empty
expect({}).to.be.empty
複製代碼

.arguments

斷言目標是一個參數對象arguments

function test () {
  expect(arguments).to.be.arguments
}
複製代碼

.equal(value)

  • value:Mixed

斷言目標嚴格等於(===)value。另外,若是設置了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,上限

斷言目標在某個區間內

expect(7).to.be.within(5, 10)
複製代碼

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

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

.instanceof(constructor)

  • constructor:Constructor,構造函數

斷言目標是構造函數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。若是設置了deep標記,則可使用點.和中括號[]來指向對象和數組中的深層屬性

// 簡單引用
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')
複製代碼

若是目標是一個數組,還能夠直接使用一個或多個數組下標做爲name來在嵌套數組中斷言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)從原來的對象變爲當前屬性的值,使得能夠在其後進一步銜接其它鏈式斷言(來針對這個屬性值進行測試)

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' })
複製代碼

注意,只有當設置了deep標記的時候,在property() name中的點(.)和中括號([])才必須使用雙反斜槓\進行轉義(爲何是雙反斜槓,在前文有說起),當沒有設置deep標記的時候,是不能進行轉義的

// 簡單指向
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

設置.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前綴結合使用會影響測試結果:

當與any結合使用時,不管是使用have仍是使用contains前綴,目標必須至少存在一個傳入的屬性名才能經過測試。注意,any或者all應當至少使用一個,不然默認爲all

當結合allcontains使用時,目標對象必須至少擁有所有傳入的屬性名,可是它也能夠擁有其它屬性名

當結合allhave使用時,目標對象必須且僅能擁有所有傳入的屬性名

// 結合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')

// 結合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

斷言目標函數會拋出一個指定錯誤或錯誤類型(使用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構造函數開始依次檢查各個可能傳入的參數。檢查一個只是消息類型不匹配可是已知的錯誤,合理的方式是先斷言該錯誤存在,而後使用.and後斷言錯誤消息不匹配

expect(fn).to.throw(ReferenceError)
  .and.not.throw(/good function/)
複製代碼

####.respondTo(method)

  • method:String

斷言目標類或對象會響應一個方法(存在這個方法)

Klass.prototype.bar = function () {}
expect(Klass).to.respondTo('bar')
expect(obj).to.respondTo('bar')
複製代碼

若是須要檢查一個構造函數是否會響應一個靜態方法(掛載在構造函數自己的方法),請查看itself標記

Klass.baz = function () {}
expect(Klass).itself.to.respondTo('baz')
複製代碼

.itself

設置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,測試器,接受一個參數表示目標值,返回一個布爾值

斷言目標值可以讓給定的測試器返回真值

expect(1).to.satisfy(function (num) { return num > 0 })
複製代碼

.closeTo(expected, delta)

  • expect:Numbre,指望值
  • delta:Numbre,範圍半徑

斷言目標數字等於expected,或在指望值的+/-delta範圍內

expect(1.5).to.be.closeTo(1, 0.5)
複製代碼

.members(set)

  • set:Array

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

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

斷言目標值出如今list數組的某個頂層位置(直接子元素,嚴格相等)

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

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

var frozenObject = Object.freeze({})

expect(frozenObject).to.be.frozen
expect({}).to.not.be.frozen
複製代碼

TDD

除了一些語法糖之外,Chai提供的assert風格的斷言和node.js包含的assert模塊很是類似。assert風格是三種斷言風格中惟一不支持鏈式調用的。 // TODO API 參考

相關文章
相關標籤/搜索