测试对于任何一门技术和工程来说都是不可或缺的重要步骤,这是非常容易理解的。但似乎很多前端的同学对测试都没有足够的认识,更谈不上使用(这里面当然也包括我自己~捂脸)。做一件事情一般需要有两个前提: 1、认识到这件事情的重要与必然性。 2、敢于接受挑战,学习新的东西并且开始实施。
对于其中一部分同学来说,是没有认识到测试的重要性,因此谈不上动机。那么这里有一个反例,也许对你认识前端单元测试的重要性有所帮助—— https://www.zhihu.com/question/278016044
那么接下来我们一起来开始学习前端单元测试的重要基础——node assert(断言)。
assert是nodejs原生提供的一个模块,该模块提供了一组简单的断言测试,可以用于测试不变量。assert存在两种模式,严格模式(strict)和遗留模式( legacy),建议仅使用严格模式。我们可以通过下面的方式访问assert的两种模式:
// 访问严格模式
var assert = require('assert').strict;
// 访问遗留模式
var assert = require('assert');
当使用严格模式时,assert.deepEqual() 和 assertStrictEqual()的效果是一样的,因为在严格模式下所有的 assert 函数都将使用严格函数模式中使用的相等性。当然,最重要的是涉及对象的错误消息将显示错误的差异,而非两个对象,这对于我们定位问题是很便利的。
当使用遗留模式时,将对所有名称中不带 strict 方法使用抽象的相等性比较,但是这通常会产生意外的结果,因此建议只使用 strict 模式。接下来我们过一下 assert 中几个比较重要的API。
assert(value[, message]);
用于检查输入的value是否为真,如果传入了message 将作为跑出错误的信息。
该方法是assert.ok();的别名。
assert.deepStrictEqual(actual, expected[, message])
在 strict 模式下可以直接使用别名 assert.deepEqual(); 作用是测试参数actual 和 expected 之间的深度相等,也就是子对象中的自身可枚举属性也会通过一定的规则进行比较。我这里列一下主要的几条规则:
1、使用 sameValue比较(使用Object.is())来比较原始值
2、使用严格相等比较来比较对象的原型
3、只考虑可枚举的资深属性(对于Error对象,始终比较名称和消息,虽然这两个不是可枚举的属性)
4、当两边的值不相同或遇到循环引用时,递归停止
以下是几个重要例子:
// 以下对象都没有自身属性
var date = new Data();
var obj1 = {}, fakeDate = {};
Object.setPrototypeOf( fakeDate, Date.prototype );
// 由于对象 obj1 和 fakeDate 原型不同,因此断言失败
assert.deepStrictEqual(obj1, fakeDate);
// 类型标签不同,失败
assert.deepStrictEqual(obj1, date);
// 因为是使用sameValue比较,通过
assert.deepStrictEqual(NAN, NAN);
可以看出,如果两个对象如果自身可枚举属性相同但是原型不同也会被断定为不相同。
assert.rejects( asyncFn[, error][, message] );
断定asyncFn不会被拒绝。
如果asyncFn是一个promise,等待promise。如果是一个函数,则立即执行该函数,等待函数返回的 promise 完成。然后检查promise是否被拒绝。如果 async 是一个函数,并且它同步抛出一个错误,那么 assert.doseNotReject( ) 将返回一个带有该错误并被拒绝的 promise, 如果函数未返回promise ,则 assert.promise将会返回一个被拒绝的 promise。这两种情况下都会跳过错误处理函数。
assert.throws( fn[, error][, message]);
期望 fn 函数抛出错误。
如果指定,error可以是 Class、 RegExp 、验证函数,每个属相将被测试严格的深度相等的验证对象、或每个属性(包括不可枚举的neme和message)将被测试严格的深度相等的错误实例。使用对象是还可以在对字符串属性进行验证时使用正则表达式。
实例:
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'
}
// 注意,将仅测试验证对象上的属性。
// 使用嵌套对象需要存在所有属性。
// 否则验证将失败。
}
);
// 使用正则表达式验证错误属性:
assert.throws(
() => {
throw err;
},
{
// `name` 和 `message` 属性是字符串,使用正则表达式将匹配字符串。
// 如果失败,则会抛出错误。
name: /^TypeError$/,
message: /错误/,
foo: 'bar',
info: {
nested: true,
// 无法对嵌套属性使用正则表达式!
baz: 'text'
},
// `reg` 属性包含一个正则表达式,
// 并且只有当验证对象包含相同的正则表达式时,
// 它才会通过。
reg: /abc/i
}
);
// 由于 `message` 和 `name` 属性不同而失败:
assert.throws(
() => {
const otherErr = new Error('未找到');
otherErr.code = 404;
throw otherErr;
},
err // 测试 `message`、 `name` 和 `code`。
);
从代码中可以看出,error中拥有的属性 fn 抛出的错误中一定要有并严格相等断言才能通过,但是反过来则不然,fn 抛出的错误中的属性即使 error 中不存在 断言仍然能正常通过。
好了,这些就是全部的内容了。
当然,以上这些内容都是文档里面看的到的,都是非常基础和浅显的内容,我只是做了一回知识的搬运工。文章的开头提到学习一个事物的两个前提,第二个前提就是个人的自我要求和自律。但凡优秀的人一定是自律的,只有这样才能驱动自己不断往前,希望看到这些文字的同学共勉....