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 参考

相关文章
相关标签/搜索