nodeAssertion断言断言模式nodeassertion分为严格模式和非严格模式,两者在使用和日志展示上有所不同(略)个人推荐使用严格模式,信息展示更清晰的介绍method//严格模式constassert=require('assert').strict;//非严格模式constassert=require('assert');抛出错误(类:assert.AssertionError)继承自--参数message[]actual[]expected[]operator[]stackStartFn[]method方法分为3类1.单个值的断言assert(value[,message])===assert.ok(value[,message])//passassert.doseNotMatch(String,regexp[,message])为真时//传递assert.match(string,regexp[,message])//匹配正则字符串时传递assert.ifError(value)//为null或undefined时注意:doseNotMatch的匹配值和match必须是String(感觉很弱);ifError值不是错误值;2.两个值的断言assert.deepStrictEqual(actual,expected[,message])//符合SameValueComparison原则,可以比较引用类型assert.notDeepStrictEqual(actual,expected[,message])//遵守SameValue比较原则,引用类型可以比较assert.strictEqual(actual,expected[,message])//符合SameValue比较原则,引用类型不能比较assert.notStrictEqual(actual,expected[,message])//符合SameValue比较原则,引用类型不能比较注意:不可比较是指同一个引用地址必须相同,比较不同的引用会报错类型;比较方法在最后Surface;参数为实际值、期望值、出错时的message|error;3.函数的断言assert.rejects(asyncFn[,error][,message])//异步函数断??言,当reject没有发生时触发assert.throws(fn[,error][,message])//同步函数断言,当函数没有抛出错误时,触发assert.doesNotReject(asyncFn[,error][,message])//异步函数断??言,当reject时触发assert.doesNotThrow(fn[,error][,message])//同步函数断言,抛出错误时触发注意:如果传入第二个参数,并且是字符串,且没有第三个参数,则第二个参数将作为消息的参数;官方说后两个断言之所以意义不大,个人认为是因为当函数抛出错误时,断言也抛出错误,而不是在断言assert中处理这个更直接处理直接在功能逻辑中有错误;error参数必须匹配函数抛出的错误,也就是说抛出的错误必须包含error参数,否则会报错可以想象,这种断言可以断言两种情况,即断言是否发生,以及断言后抛出的错误是否符合预期的错误(当有嵌套对象时,嵌套对象结构必须是预期的和实际的)samecanbepassed);//根据官方的例子,可以传consterr=newTypeError('errorvalue');错误代码=404;err.foo='酒吧';err.info={nested:true,baz:'text'};err.reg=/abc/i;assert.throws(()=>{throwerr;},{name:'TypeError',message:'Errorvalue',info:{nested:true,baz:'text'}});//错误,因为aconst断言对象上不存在err=newTypeError('Errorvalue');错误代码=404;err.foo='bar';err.info={nested:true,baz:'text'};err.reg=/abc/i;assert.throws(()=>{throwerr;},{name:'TypeError',message:'Errorvalue',info:{nested:true,baz:'text'},a:1});//正确,虽然断言上的属性没有a,但是其他属性可以通过测试consterr=newTypeError('错误值');err.code=404;err.foo='bar';err.a=1err.info={nested:true,baz:'text'};err.reg=/abc/i;assert.throws(()=>{throwerr;},{name:'TypeError',message:'errorvalue',info:{nested:true,baz:'text'}});严格相等的规则1.基本类型的比较使用Object.is()进行比较;2.对象的类型标签,比如官方例子中的;//以下对象没有自己的属性。constdate=newDate();constobject={};constfakeDate={};Object.setPrototypeOf(fakeDate,Date.prototype);//注意,官方不推荐setPrototyOf方法,我用的是Object.create()相反,让fakeDate=Object.create(date)//类型标签不同:assert.deepStrictEqual(date,fakeDate);//AssertionError:Expectedinputstobestrictlydeep-equal://+actual-expected////+2018-04-26T00:49:08.604Z//-Date{}乍一看date的原型链和fakeDate一模一样,其实一个是具体时间,一个是日期对象3.比较原型//在上面的代码中,原型是不同的:assert.deepStrictEqual(object,fakeDate);//AssertionError:Expectedinputstobestrictlydeepequal://+actual-expected////+{}//-日期{}4.这里只考虑可枚举的自属性。这里记忆的时候可以考虑一下Symbol属性。5.Error的特例,因为需要比较不可枚举的属性名和消息6。objectwrapper作为对象,这里比较解封装后的值。就是String(),Number()等,因为本质上使用这些方法进行类型转换,其实就是把基本类型转换成对象,否则基本类型上就没有方法可以调用了,所以翻译成一个对象包装器(我认为还可以)。比较的是比较函数调用后的结果,如官方例子://解封装后的数字不同:assert.deepStrictEqual(newNumber(1),newNumber(2));//AssertionError:Expectedinputsto严格深度相等://+实际-预期////+[Number:1]//-[Number:2]断言。deepStrictEqual(newString('foo'),Object('foo'));//通过,因为对象和展开的字符串是相同的。7.Object的属性,Map的键名和Set的子项,它们的比较是无序比较8.当两边的值不一样或者遇到循环引用时,递归停止。这意味着当发现比较的两侧不同时,比较就会停止,直到结束才会继续比较。当node在比较过程中发现有循环引用,就停止比较(报错信息暂时未知)。9、WeakMap和WeakSet的比较不依赖于它们的值。WeakMap和WeakSet的内部键值对是不能比较的,因为是弱引用,所以比较的时候可能有值也可能没有,所以两个WeakMap比较的时候可以默认相等,但是当WeakMap强制添加一个强引用的键值对,必须要求同一个WeakMap才有这个强引用的键值对。constweakMap1=newWeakMap();constweakMap2=newWeakMap([[{},{}]]);constweakMap3=newWeakMap();weakMap3.unequal=true;assert.deepStrictEqual(weakMap1,weakMap2);//已通过,因为无法比较条目。//失败,因为weakMap3有一个weakMap1没有的属性:assert.deepStrictEqual(weakMap1,weakMap3);//AssertionError:Expectedinputstobestrictlydeep-equal://+actual-expected////WeakMap{//+[项目未知]//-[项目未知],//-不等:真//}