node Assertion 断言
断言模式
node的断言分为严格模式和非严格模式,这两者在使用和log展示上有不同之处(略)
个人推荐使用严格模式,信息展示更加清晰
引入方式:
//严格模式
const assert = require('assert').strict;
//非严格模式
const assert = require('assert');
抛出错误(Class: assert.AssertionError)
继承于
-- 参数
message
[] actual
[] expected
[] operator
[] stackStartFn
[]
method
方法分为3类
一、 单个值的断言
assert(value[, message])
===assert.ok(value[, message])
//是truthy时通过assert.doseNotMatch(String,regexp[,message])
//正则不匹配字符串时通过assert.match(string, regexp[, message])
//正则匹配字符串时通过assert.ifError(value)
//是null
或者undefined
时通过
注意点:
- doseNotMatch和match的匹配值必须是String(感觉很弱);
- ifError的值不是判断falsly值;
二、 两个值的断言
assert.deepStrictEqual(actual, expected[, message])
//符合SameValue Comparison原则,引用类型可比较assert.notDeepStrictEqual(actual, expected[, message])
//符合SameValue Comparison原则,引用类型可比较assert.strictEqual(actual, expected[, message])
//符合SameValue Comparison原则,引用类型不可比较assert.notStrictEqual(actual, expected[, message])
//符合SameValue Comparison原则,引用类型不可比较
注意点:
- 不可比较的意思是必须是同一个引用地址才相同,比较不同引用类型时报错;
- 比较的方法在最后面;
- 参数分别是实际值,期望值,当发生错误时的message|error;
三、对函数的断言
assert.rejects(asyncFn[, error][, message])
//异步函数断言,当reject没有发生时触发assert.throws(fn[, error][, message])
//同步函数断言,当函数没有抛出错误时触发assert.doesNotReject(asyncFn[, error][, message])
//异步函数断言,当reject触发assert.doesNotThrow(fn[, error][, message])
//同步函数断言,抛出错误时触发
注意点:
- 如果第二个参数传递,且是字符串,而且没有第三个参数的时候,会将第二个参数作为message的传参;
- 官方说后面两个断言的意义不大的原因,个人认为是因为当函数抛出错误的时候断言也抛出错误,与其在断言assert中处理这个错误,不如直接在函数逻辑中处理更为直接;
- error参数必须和函数抛出的错误相匹配,也就是说判断抛出的错误必须包含error参数,不然报错。可以想到这种断言可以断言两种情况,即是否发生断言,而发生断言后抛出的错误是否与预期的error相匹配(当有嵌套的对象时,嵌套的对象结构必须是预期和实际一样才能通过);
//以官方例子为准,此时能通过
const err = new TypeError('错误值');
err.code = 404;
err.foo = 'bar';
err.info = {
nested: true,
baz: 'text'
};
err.reg = /abc/i;
assert.throws(
() => {
throw err;
}, {
name: 'TypeError',
message: '错误值',
info: {
nested: true,
baz: 'text'
}
}
);
//错误, 因为断言的对象上不存在a
const err = new TypeError('错误值');
err.code = 404;
err.foo = 'bar';
err.info = {
nested: true,
baz: 'text'
};
err.reg = /abc/i;
assert.throws(
() => {
throw err;
}, {
name: 'TypeError',
message: '错误值',
info: {
nested: true,
baz: 'text'
},
a:1
}
);
//正确,虽然断言上的属性没有a,但是其他属性都能通过检验
const err = new TypeError('错误值');
err.code = 404;
err.foo = 'bar';
err.a = 1
err.info = {
nested: true,
baz: 'text'
};
err.reg = /abc/i;
assert.throws(
() => {
throw err;
}, {
name: 'TypeError',
message: '错误值',
info: {
nested: true,
baz: 'text'
}
}
);
严格相等的规则
1.基础类型的比较使用Object.is()
比较;
2.对象的类型标签 比如官方的例子中;
// 以下对象没有自身属性。
const date = new Date();
const object = {};
const fakeDate = {};
Object.setPrototypeOf(fakeDate, Date.prototype);
//注意,setPrototyOf方法官方不推荐,我使用的Object.create()替代 let fakeDate = Object.create(date)
// 类型标签不同:
assert.deepStrictEqual(date, fakeDate);
// AssertionError: Expected inputs to be strictly deep-equal:
// + actual - expected
//
// + 2018-04-26T00:49:08.604Z
// - Date {}
咋看之下date的原型链和fakeDate的是一模一样的,但是实质上一个是具体的时间,而另外一个是date对象
3.比较原型
// 如上代码中,原型不同:
assert.deepStrictEqual(object, fakeDate);
// AssertionError: Expected inputs to be strictly deep- equal:
// + actual - expected
//
// + {}
// - Date {}
4.只考虑可枚举的自身属性
这里记忆的时候可以把Symbol属性考虑上
5.特例Error
,因为需要比较不可枚举属性names
和 messages
6.对象封装器作为对象和解封装后的值都进行比较
这里指的是String()
、Number()
等等,因为本质上使用这些方法进行类型转换其实是将基础类型转成对象处理,不然在基础类型上面是不会有方法可以调用的,所以翻译成对象封装器(我觉得还行吧)。比较的时候是比较函数调用之后的结果,比如官方例子:
// 解封装后的数字不同:
assert.deepStrictEqual(new Number(1), new Number(2));
// AssertionError: Expected inputs to be strictly deep-equal:
// + actual - expected
//
// + [Number: 1]
// - [Number: 2]
assert.deepStrictEqual(new String('foo'), Object('foo'));
// 通过,因为对象与解封装后的字符串都是相同的。
7.Object的属性、Map的键名和Set的子项, 他们的比较是无序比较
8.当两边的值不相同或遇到循环引用时,递归停止。
这个的意思是当发现比较的双方是不同的时候,比较就停止,不会一直比较到最后。而node发现比较过程中存在循环引用的时候就停止比较(报错信息暂时不知道)
9.WeakMap 和 WeakSet 的比较不依赖于它们的值。
WeakMap和WeakSet的内在键值对是无法比较的,因为是弱引用,所以当比较的时候也许有值也许没有,所以当两个WeakMap比较的时候默认是可以相等的,但是当WeakMap强行添加一个强引用的键值对,就必须要求同样的WeakMap具备这个强引用的键值对。
const weakMap1 = new WeakMap();
const weakMap2 = new WeakMap([[{}, {}]]);
const weakMap3 = new WeakMap();
weakMap3.unequal = true;
assert.deepStrictEqual(weakMap1, weakMap2);
// 通过,因为无法比较条目。
// 失败,因为 weakMap3 有一个 weakMap1 不包含的属性:
assert.deepStrictEqual(weakMap1, weakMap3);
// AssertionError: Expected inputs to be strictly deep-equal:
// + actual - expected
//
// WeakMap {
// + [items unknown]
// - [items unknown],
// - unequal: true
// }