详解Chai.js断言库API中文文档
Chai.js断言库API中文文档
基于chai.js官方API文档翻译。仅列出BDD风格的expect/shouldAPI。TDD风格的AssertAPI由于不打算使用,暂时不放,后续可能会更新。
BDD
expect和should是BDD风格的,二者使用相同的链式语言来组织断言,但不同在于他们初始化断言的方式:expect使用构造函数来创建断言对象实例,而should通过为Object.prototype新增方法来实现断言(所以should不支持IE);expect直接指向chai.expect,而should则是chai.should()。
个人比较建议使用expect,should不仅不兼容IE,在某些情况下还需要改变断言方式来填坑。详细的比较可以看看官网AssertionStyles,说的很清楚。
varchai=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
设置deep标记,然后使用equal和property断言。该标记可以让其后的断言不是比较对象本身,而是递归比较对象的键值对
expect(foo).to.deep.equal({bar:'baz'}) expect({foo:{bar:{baz:'quux'}}}) .to.have.deep.property('foo.bar.baz','quux')
deep.property中的特殊符号可以使用双反斜杠进行转义(第一个反斜杠是在字符串参数中对第二个反斜杠进行转义,第二个反斜杠用于在property中进行转义)
vardeepCss={'.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,被测试的值的类型
a和an断言即可作为语言链又可作为断言使用
//类型断言 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(newError).to.be.an('error'); expect(newPromise).to.be.a('promise'); expect(newFloat32Array()).to.be.a('float32array'); expect(Symbol()).to.be.a('symbol'); //es6overrides expect({[Symbol.toStringTag]:()=>'foo'}).to.be.a('foo'); //languagechain 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
varfoo='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
functiontest(){ 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的一个实例
varTea=function(name){this.name=name}, Chai=newTea('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标记,则可以使用点.和中括号[]来指向对象和数组中的深层属性
//简单引用 varobj={foo:'bar'} expect(obj).to.have.property('foo') expect(pbj).to.have.property('foo','bar') //深层引用 vardeepObj={ 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
vararr=[ ['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标记的时候,是不能进行转义的
//简单指向 varcss={'.link[target]':42} expect(css).to.have.property('.link[target]',42) //深度指向 vardeepCss={'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属性名
断言目标包含传入的属性名。与any,all,contains或者have前缀结合使用会影响测试结果:
当与any结合使用时,无论是使用have还是使用contains前缀,目标必须至少存在一个传入的属性名才能通过测试。注意,any或者all应当至少使用一个,否则默认为all
当结合all和contains使用时,目标对象必须至少拥有全部传入的属性名,但是它也可以拥有其它属性名
当结合all和have使用时,目标对象必须且仅能拥有全部传入的属性名
//结合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计算),也可使用正则表达式或者字符串来检测错误消息
varerr=newRefernceError('thisisabadfunction') varfn=function(){throwerr} expect(fn).to.throw(ReferenceError) expect(fn).to.throw(Error) expect(fn).to.throw(/badfunction/) expect(fn).to.not.throw('goodfunction') expect(fn).to.throw(ReferrenceError,/badfunction/) expect(fn).to.throw(err)
注意,当一个抛错断言被否定了(前面有.not),那么它会从Error构造函数开始依次检查各个可能传入的参数。检查一个只是消息类型不匹配但是已知的错误,合理的方式是先断言该错误存在,然后使用.and后断言错误消息不匹配
expect(fn).to.throw(ReferenceError) .and.not.throw(/goodfunction/)
.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断言
functionFoo(){} 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){returnnum>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']) //严格相等,所以对象类的值必须为同一个引用才能被判定为相等 varthree=[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,属性名
断言目标方法会改变指定对象的指定属性
varobj={val:10} varfn=function(){obj.val+=3} varnoChangeFn=function(){return'bar'+'baz'} expect(fn).to.change(obj,'val')
.increase(object,property)
- object:Object,对象
- property:String,属性名
断言目标方法会增加指定对象的属性
varobj={val:10} varfn=function(){obj.val=15} expect(fn).to.increase(obj,val)
.decrease(object,property)
- object:Object,对象
- property:String,属性名
断言目标方法会减少指定对象的属性
varobj={val:10} varfn=function(){obj.val=5} expect(fn).to.decrease(obj,val)
.extensible
断言目标对象是可扩展的(可以添加新的属性)
varnonExtensibleObject=Object.preventExtensions({}) varsealedObject=Object.seal({}) varfrozenObject=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
断言目标对象是封闭的(无法添加新的属性并且存在的属性不能被删除但可以被修改)
varsealedObject=Object.seal({}) varfrozenObject=Object.freeze({}) expect(sealedObject).to.be.sealed expect(frozenObject).to.be.sealed expect({}).to.not.be.sealed
.frozen
断言目标对象是冻结的(无法添加新的属性并且存在的属性不能被删除和修改)
varfrozenObject=Object.freeze({}) expect(frozenObject).to.be.frozen expect({}).to.not.be.frozen
TDD
除了一些语法糖以外,Chai提供的assert风格的断言和node.js包含的assert模块非常相似。assert风格是三种断言风格中唯一不支持链式调用的。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。