node.js学习之断言assert的使用示例


Posted in Javascript onSeptember 28, 2017

一. 简介

断言是编程术语,表示为一些布尔表达式,程序员相信在程序中的某个特定点该表达式值为真,可以在任何时候启用和禁用断言验证,因此可以在测试时启用断言而在部署时禁用断言。同样,程序投入运行后,最终用户在遇到问题时可以重新启用断言。

使用断言可以创建更稳定、品质更好且 不易于出错的代码。当需要在一个值为FALSE时中断当前操作的话,可以使用断言。【单元测试】必须使用断言。

Node提供了 10 多个断言测试的函数,用于测试不变式,我在文章中中将这 10 多个函数进行了分组,方便理解记忆。

【提示】在本文章中,expected 代表预期值,actual 代表实际值, message 代表自定义信息

二. 判断值是否为真值

判断值是否为真值有以下两个断言测试函数

2.1 assert(value[, message])

这个测试函数在 【Boolean(value)】 为 【true】时通过断言测试,否则抛出 【AssertionError】

const assert = require("assert");

assert("blue","第一个值为false时以我为错误信息抛出");

assert(true,"第一个值为false时以我为错误信息抛出");

上面一段代码由于【Boolean(value)】全部为 true,所以全部通过断言测试

assert(false,"第一个值为false时以我为错误信息抛出");

// AssertionError [ERR_ASSERTION]: 第一个值为false时以我为错误信息抛出

上面代码中 value 为false,则抛出一个带有 message 属性的 【AssertionError】,其中 message 属性的值等于传入的 message 参数的值。 【如果 message 参数为 undefined,则赋予默认的错误信息】。

assert(false);
// AssertionError [ERR_ASSERTION]: false == true

上面代码由于没有指定【message】参数,抛出的为默认错误信息的【AssertionError】

2.2 assert.ok(value[, message])

assert.ok() assert()的作用是一样的,都是测试【value】是否为真值。而且用法也一样,所以可以将assert()视为assert.ok()的语法糖

const assert = require("assert");
assert.ok(true);
assert.ok(1);

上面代码【Boolean(value)】全部为 true,所以全部断言通过,下面是断言不通过的情况,分别列出了默认错误信息

assert.ok(0);
//AssertionError [ERR_ASSERTION]: 0 == true

assert.ok(false);
//AssertionError [ERR_ASSERTION]: false == true

assert.ok(false,"自定义错误信息");
//AssertionError [ERR_ASSERTION]: 自定义错误信息

三. 判断预期值和实际值相等(==)

这一组里面有两个测试函数,用于测试预期值与实际值是否相等,如果相等则断言通过,否则抛出 【AssertionError】

3.1 assert.equal(actual, expected[, message])

assert.equal()用于测试期望值和实际值是否相等,【在值类型的时候比较的是两个值是否相等,当预期值和实际值为引用类型的时候,比较的是值得引用】

assert.equal(1, 1);
assert.equal("1", 1);

上面代码是对值类型进行的比较,说明equal()在内部使用的是(==),而非严格相等,待会儿我会总结到严格相等(===)

assert.equal({},{},"AssertionError");
assert.equal(() => { }, () => { }, "AssertionError");
assert.equal([],[],'AssertionError');

上面三个表达式都会抛出【message】属性值为'AssertionError'的【AssertionError】对象,【所以当值为引用类型的时候,equal()比较的是值得引用,因此两个引用类型的值是没法通过equal()断言的】

const obj={};
assert.equal(obj,obj);
// 断言通过

上面代码由于比较的是同一个对象,两个值得引用相等,所以断言通过。

3.2 assert.deepEqual(actual, expected[, message])

同样也是测试 预期值 和 实际值 是否相等,使用的仍然是(==),但是与equal不同的是,【deepEqual()在对引用类型进行比较的时候,不是对值的引用进行比较,而是比较的对象的属性值】

const a = 'Blue', b = 'Pink';
assert.deepEqual(a,a,'actual unequal to expected');
// 断言通过
assert.deepEqual(a,b,'actual unequal to expected');
// AssertionError [ERR_ASSERTION]: actual unequal to expected

上面是对值类型进行的比较,和equal()没有任何的区别

const obj1 = { name: "foo", gender: "men" },
 obj2 = { name: "foo", gender: "men" },
 obj3 = { name: "bar", gender: "men" }
assert.deepEqual(obj1, obj2, 'actual unequal to expected');
// 断言通过
assert.deepEqual(obj1, obj3, 'actual unequal to expected');
// AssertionError [ERR_ASSERTION]: actual unequal to expected

上面代码是对引用类型的比较,可以看出【deepEqual() 】比较的是属性值,而非引用,这是与equal()不同的地方。

【注意!!】deepEqual()只测试可枚举的自身属性,不测试对象的原型、连接符、或不可枚举的属性(这些情况使用 assert.deepStrictEqual() ,稍后会总结到)

const son1 = Object.create(obj1),
 son2 = Object.create(obj2);

son1.name="Summer";
son2.name="Summer";

assert.deepEqual(son1,son2,"actual unequal to expected");
// 断言通过

上面代码中 son1 和 son2 分别继承与两个不同的对象,都拥有 name 为 “Summer” 的属性,最后的的结果是通过,说明【deepEqual()不测试对象的原型】

const ena = {}, enb = {};
Object.defineProperties(ena,{
 name:{
 value:"Blue"
 },
 hobby:{
 value:"foo",
 enumerable:false //可枚举性设置为false
 }
});
Object.defineProperties(enb,{
 name:{
 value:"Blue"
 },
 hobby:{
 value:"bar",
 enumerable:false //可枚举性设置为false
 }
})
assert.deepEqual(ena,enb,"actual unequal to expected") 
//ok,actual equal to expected

上面代码中 ena 和 enb 用于相同的可枚举属性【name】,有着值不同的不可枚举属性【hobby】,说明【deepEqual()不测试对象的不可枚举的属性】

四. 判断预期值和实际值全等(===)

这组测试函数是用于判断预期值和实际值是否深度相等的,内部使用的是(===),所以对象的原型也会进行比较,值得类型也是比较的范围。这组也有两个测试函数。

4.1 assert.deepStrictEqual(actual, expected[, message])

由于内部使用的是全等(===),所以对象的原型也会计入比较的范围

const obj1 = { name: "foo", gender: "men" },
 obj2 = { name: "bar", gender: "men" }
const son1 = Object.create(obj1),
 son2 = Object.create(obj2);
son1.name = "Summer";
son2.name = "Summer";
assert.deepEqual(son1, son2, "actual unequal to expected");
//断言通过
assert.deepStrictEqual(son1, son2, "actual unequal to expected")
//AssertionError [ERR_ASSERTION]: actual unequal to expected

上面代码使用了deepEqual()deepStrictEqual()进行了断言测试,son1 和 son2 分别继承与两个不同的对象,但是拥有相同的属性值。可以看出【deepEqual()是不会考虑对象的原型的,deepStrictEqual()将原型对象列入了比较对象】

4.2 assert.strictEqual(actual, expected[, message])

strictEqual()equal()的加强,考虑了数据类型;如果actual === expected,则断言通过,否则抛出AssertionError,message?message:默认错误信息。

assert.strictEqual(1, 2);
// 抛出 AssertionError: 1 === 2

assert.strictEqual(1, 1);
// 测试通过。

assert.strictEqual(1, '1');
// 抛出 AssertionError: 1 === '1'

assert.equal(1, '1');
// 测试通过。

【提示!!】对引用类型还是永远通不过【strictEqual()】断言测试

五. 判断预期值和实际值不相等(!=)

上面总结到了判断预期值和实际值相等,这儿总结一下判断预期值和实际值不想等的两个测试函数,实际上就是上面 (三) 的逆运算。

5.1 assert.notEqual(actual, expected[, message])

notEqual()】为 【equal() 】的逆运算,如果 actual!= expected 则断言通过,同样对于值类型是单纯对值进行比较,对应引用类型比较的是值得引用

assert.notEqual("1", "2");
// 断言通过

assert.notEqual("1", 2);
// 断言通过

assert.notEqual("1", 1);
// AssertionError [ERR_ASSERTION]: '1' != 1

上面代码是对值类型进行的比较,第三个表达式的默认信息可以看出内部使用的是(!=)

assert.notEqual({ a: "foo" }, { a: "foo" });

assert.notEqual(() => { }, () => { });

assert.notEqual([], []);

上面的代码是对引用类型进行的断言测试,【notEqual() 】对于两个对象的测试通过是一个【恒成立】的结果。

5.2 assert.notDeepEqual(actual, expected[, message])

notDeepEqual() 】为 【deepEqual() 】的逆运算,如果 actual!= expected 则断言通过,不同于notEqual()的是对于引用类型是对值进行判断,不比对原型、不可枚举属性,只比对自有可枚举属性,断言通过。

const obj1 = { a: "foo" },
 obj2 = { b: "bar" },
 obj3 = Object.create(obj1);

assert.notDeepEqual(obj1,obj1,'actual equal to expected');
// AssertionError [ERR_ASSERTION]: actual equal to expected

assert.notDeepEqual(obj1,obj2,'actual equal to expected');
// 断言通过

assert.notDeepEqual(obj1,obj3,'actual equal to expected');
// 断言通过

上面代码中最后一个表达式断言通过,说明【不比对原型、不可枚举属性,只比对自有可枚举属性】

【注意!!】与notEqual的区别,也就是deepEqual和equal的区别,在引用数据类型的时候,deepEqual是比较的值而非引用,equal对比的是引用,所以引用类型在equal的时候是永远无法通过断言测试的,以此类推,引用类型在notEqual时是永远否可以通过断言测试的。

六. 判断预期值和实际值严格不相等(!==)

上面总结到了判断预期值和实际值严格相等,这儿总结一下判断预期值和实际值严格不相等的两个测试函数,实际上就是上面 (四) 的逆运算

6.1 assert.notStrictEqual(actual, expected[, message])

如果actual与expected不 !== 则断言通过, 与 assert.deepStrictEqual() 相反

assert.notStrictEqual("1", 1);
// 断言通过

assert.notStrictEqual("1", "1");
// AssertionError [ERR_ASSERTION]: '1' !== '1'

上面代码是对值类型进行的断言测试,可以看出【notStrictEqual() 】考虑了数据类型

assert.notStrictEqual({ a: "foo" }, { a: "foo" });
assert.notStrictEqual(() => { }, () => { });
assert.notStrictEqual([], []);

上面代码是对引用类型的测试,全部通过,以上表达式是恒通过的。

6.2 assert.notDeepStrictEqual(actual, expected[, message])

notDeepStrictEqual()就是deepStrictEqual()的逆运算,如果 actual !== expected 则断言通过,否则抛出AssertionError。

assert.notDeepStrictEqual({ a: '1' }, { a: 1 });
//断言通过

assert.notDeepStrictEqual({ a: '1' }, { a: "1" });
//AssertionError [ERR_ASSERTION]: { a: '1' } notDeepStrictEqual { a: '1' }

七. 断言错误并抛出

这一组有 四 个(可以说是 三 个)测试函数,是对错误进行的处理。

7.1 assert.fail(message)

这个测试函数不多说,可以看错是下一个函数的重载,用于主动抛出带有【message】属性的【AssertionError】对象

assert.fail("自定义错误信息");
// AssertionError [ERR_ASSERTION]: 自定义错误信息

7.2 assert.fail(actual, expected[, message[, operator[, stackStartFunction]]])

该测试函数用于主动抛出自定义错误信息,抛出错误信息格式:【actual 参数 + operator 参数 + expected 参数】

assert.fail("BLUE","PINK");  
// AssertionError [ERR_ASSERTION]: 'BLUE' != 'PINK'

上面代码不提供【message】和【operator】,则【operator】默认为 【!=】

assert.fail("BLUE","PINK","自定义的错误信息");  
// AssertionError [ERR_ASSERTION]: 自定义的错误信息

assert.fail("BLUE","PINK","自定义的错误信息","?",()=>{
  console.log("hello");
 });
// AssertionError [ERR_ASSERTION]: 自定义的错误信息

上面代码提供【message】,这时候 【actual】、【operator】、【expected】等参数会被列入错误对象属性中

assert.fail("BLUE","PINK",undefined);
// AssertionError [ERR_ASSERTION]: 'BLUE' undefined 'PINK'

assert.fail("BLUE","PINK",undefined,"?");
// AssertionError [ERR_ASSERTION]: 'BLUE' ? 'PINK'

上面代码是【message】为 undefined 时,会检测【operator】参数,【operator?operator:undefined

7.3 assert.throws(block,error, message)

参数说明:

block | Function

error | RegExp | Function

message | any

【说明!!】如果block抛出的错误满足error参数,也就是抛出错误与期望一致,则断言通过,否则抛出block中的错误,如果block不抛出错误,则抛出【AssertionError 】。

【提示!!】error 参数可以是构造函数、正则表达式、或自定义函数。

assert.throws(
 () => {
  throw new Error('错误信息');
 },
 Error
);

上面代码中 error 参数为构造函数,【block】抛出的错误与预期的一致,所以断言通过。

assert.throws(
 () => {
  throw new Error('错误信息');
 },
 /错误/
);

上面代码中 error 参数为正则表达式,【block】抛出的错误满足正则表达式,所以断言通过。

【注意!!】error 参数不能是字符串。 如果第二个参数是字符串,则视为省略 error 参数,传入的字符串会被用于 【message】 参数,

// 这是错误的!不要这么做!
assert.throws(myFunction, '错误信息', '没有抛出期望的信息');

// 应该这么做。
assert.throws(myFunction, /错误信息/, '没有抛出期望的信息');

下面代码,【error】 参数为自定义函数

assert.throws(
 () => {
  throw new Error('错误信息');
 },
 function (err) {
  if ((err instanceof Error) && /错误/.test(err)) {
   return true;
  }
 },
 '不是期望的错误'
);

7.4 assert.doesNotThrow(block, error, message)

【说明!!】预期的错误和实际的错误一致时,不抛出实际错误,抛出AssertionError,不一致则抛出实际错误信息

assert.doesNotThrow(
 () => {
 throw new TypeError('错误信息');
 },
 SyntaxError
);

以上例子会抛出 TypeError,因为在断言中没有匹配的错误类型

assert.doesNotThrow(
 () => {
 throw new TypeError('错误信息');
 },
 TypeError
);

以上例子会抛出一个带有 Got unwanted exception (TypeError).. 信息的 AssertionError

assert.doesNotThrow(
 () => {
 throw new TypeError('错误信息');
 },
 TypeError,
 '抛出错误'
);
// 抛出 AssertionError: Got unwanted exception (TypeError). 抛出错误

上面代码说明:如果抛出了 AssertionError 且有给 message 参数传值,则 message 参数的值会被附加到 AssertionError 的信息中

八. 判断值是否为真

这儿只有一个测试函数了

8.1 assert.ifError(value)

如果value的值为真或者可以转换成true,则抛出value,否则断言通过。

assert.ifError(true); 
//抛出true

assert.ifError(false);
//断言通过

上面代码中是直接给出的 布尔 类型的值,如果值为 true 则会将该值抛出,否则什么也不做

assert.ifError(0);
//断言通过

assert.ifError("0");
//抛出 "0"

assert.ifError(1);
//抛出 1

assert.ifError(new Error());
//抛出 Error,对象名称

上面代码中全部是通过 Boolean(value) 转换之后再进行的测试,利用这个特性我们可以将此测试函数用于测试回调函数的 error 参数。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对三水点靠木的支持。

Javascript 相关文章推荐
页面中iframe相互传值传参
Dec 13 Javascript
jQuery 获取URL参数的插件
Mar 04 Javascript
jQuery AJAX实现调用页面后台方法和web服务定义的方法分享
Mar 01 Javascript
js将long日期格式转换为标准日期格式实现思路
Apr 07 Javascript
JS+CSS设置img在DIV中只显示Img垂直居中的部分
Oct 24 Javascript
jQuery实现列表自动滚动循环滚动展示新闻
Aug 22 Javascript
AngularJS入门教程之学习环境搭建
Dec 06 Javascript
Bootstrap Paginator分页插件使用方法详解
May 30 Javascript
KnockoutJS 3.X API 第四章之表单textInput、hasFocus、checked绑定
Oct 11 Javascript
jQuery EasyUI的TreeGrid查询功能实现方法
Aug 08 jQuery
利用SpringMVC过滤器解决vue跨域请求的问题
Feb 10 Javascript
jQuery 实现DOM元素拖拽交换位置的实例代码
Jul 14 jQuery
vue-router+vuex addRoutes实现路由动态加载及菜单动态加载
Sep 28 #Javascript
node.js学习之事件模块Events的使用示例
Sep 28 #Javascript
es6中的解构赋值、扩展运算符和rest参数使用详解
Sep 28 #Javascript
JS获取日期的方法实例【昨天,今天,明天,前n天,后n天的日期】
Sep 28 #Javascript
jquery实现左右轮播图效果
Sep 28 #jQuery
bootstrap table实现点击翻页功能 可记录上下页选中的行
Sep 28 #Javascript
JavaScript判断输入是否为数字类型的方法总结
Sep 28 #Javascript
You might like
php中去除所有js,html,css代码
2010/10/12 PHP
php数组函数序列之array_sum() - 计算数组元素值之和
2011/10/29 PHP
PHP变量的定义、可变变量、变量引用、销毁方法
2013/12/20 PHP
CentOS 安装 PHP5.5+Redis+XDebug+Nginx+MySQL全纪录
2015/03/25 PHP
记Laravel调用Gin接口调用formData上传文件的实现方法
2019/12/12 PHP
在网页中控制wmplayer播放器
2006/07/01 Javascript
基于jQuery实现图片的前进与后退功能
2013/04/24 Javascript
PHP中使用微秒计算脚本执行时间例子
2014/11/19 Javascript
jQuery检测输入的字符串包含的中英文的数量
2015/04/17 Javascript
nodejs导出excel的方法
2015/06/30 NodeJs
angularjs学习笔记之简单介绍
2015/09/26 Javascript
Bootstrap布局方式详解
2016/05/27 Javascript
防止Node.js中错误导致进程阻塞的办法
2016/08/11 Javascript
BootStrap中的表单大全
2016/09/07 Javascript
BootStrap整体框架之基础布局组件
2016/12/15 Javascript
PHP实现本地图片上传和验证功能
2017/02/27 Javascript
完美解决spring websocket自动断开连接再创建引发的问题
2017/03/02 Javascript
js登录滑动验证的实现(不滑动无法登陆)
2018/01/03 Javascript
基于JavaScript中标识符的命名规则介绍
2018/01/06 Javascript
Vue的轮播图组件实现方法
2018/03/03 Javascript
vue cli3适配所有端方案的实现
2020/04/13 Javascript
基于javascript的无缝滚动动画1
2020/08/07 Javascript
[03:55]显微镜下的DOTA2特别篇——430灰烬之灵神级操作
2014/06/24 DOTA
Python 提取dict转换为xml/json/table并输出的实现代码
2016/08/28 Python
Python实现的微信公众号群发图片与文本消息功能实例详解
2017/06/30 Python
Windows下python3.7安装教程
2018/07/31 Python
详解python--模拟轮盘抽奖游戏
2019/04/12 Python
使用python-opencv读取视频,计算视频总帧数及FPS的实现
2019/12/10 Python
Python逐行读取文件内容的方法总结
2020/02/14 Python
Python中import导入不同目录的模块方法详解
2020/02/18 Python
Python telnet登陆功能实现代码
2020/04/16 Python
python实现学生信息管理系统(精简版)
2020/11/27 Python
在SQL Server中创建数据库主要有那种方式
2013/09/10 面试题
夜大毕业生自我鉴定
2013/10/31 职场文书
高中毕业自我鉴定
2013/12/19 职场文书
《学会待客》教学反思
2014/02/22 职场文书