单元测试断言库:chai.js中文文档

2023-10-07 02:38

本文主要是介绍单元测试断言库:chai.js中文文档,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

原文档地址:https://www.chaijs.com/api/bdd/


BDD风格包含expect和should。它们以相同的链式结构进行断言,它们的不同之处在于初始的断言构造。可以查看风格指南来进行比较。


译注:风格指南中相关的翻译如下:
(鉴于有代码所以没有放入引用格式而是用分割线与正文区分)

BDD风格有两种风格:expect和should。两者都使用相同的可链接语言来构造断言,但它们在最初构造断言的方式上有所不同。在使用should的情况下将可能会产生一些问题,这也有一些方式去克服这些问题。
Expect: BDD风格暴露expect或should接口。在这两种情况下,你可以用自然语言的形式来链接断言。 Expect也允许你在任何可能发生的断言失败之前添加任意信息。当与布尔值、数字等非描述性主题一起连用时,这将十分好用。
Should: Should允许你使用与Expect接口相同的链式断言风格,然而当should风格启动链式断言时将可能在IE浏览器下存在一些问题,因此要注意浏览器兼容性。
两者间的区别:
首先要注意的是,expect的引入仅需要引入expect函数,而should的引入需要引入should的函数执行。

var chai = require('chai'), expect = chai.expect, should = chai.should();

expect接口提供了一个函数作为链接语言断言的起点。它适用于node.js和所有浏览器。
should接口实例化对象原型的产生单一实例来进行断言。它适用于node.js以及除Internet Explorer之外的所有现代浏览器。
Should需要额外注意的:
should通过实例化对象的原型进行工作,所以在一些情况下他将可能不会工作


API参照:

链式语言结构
使用以下的链式供给(getter)来提高你断言的可阅读性啊。

译注:以下的链式结构语句单纯是为了提高阅读性所加的一些自然语句。实际上是没有作用的。后续的api才是断言所用的接口。

Chains

  • to
  • be
  • been
  • is
  • that
  • which
  • and
  • has
  • have
  • with
  • at
  • of
  • same
  • but
  • does
  • still

.not
否定在其之后链接的所有断言。

expect(function () {}).to.not.throw();
expect({a: 1}).to.not.have.property('b');
expect([1, 2]).to.be.an('array').that.does.not.include(3);

这仅意味这你可以使用.not来对断言进行否定,而不意味着你应该这样去做。能力越大责任就越大。通常最好的做法是产生一个期待输出的断言,而不是产生无数个不会发生的非期待断言之一。

expect(2).to.equal(2); // 推荐的方式
expect(2).to.not.equal(1); // 不推荐的方式

.deep
将.equal, .include, .members, .keys 和 .property放在.deep链式之后将导致使用深度相等的方式来代替严格相等(===)

// 目标对象深度(但不严格) 等于 `{a: 1}`
expect({a: 1}).to.deep.equal({a: 1});
expect({a: 1}).to.not.equal({a: 1});// 目标数组深度(但不严格) 包含 `{a: 1}`
expect([{a: 1}]).to.deep.include({a: 1});
expect([{a: 1}]).to.not.include({a: 1});// 目标对象深度(但不严格) 包含 `x: {a: 1}`
expect({x: {a: 1}}).to.deep.include({x: {a: 1}});
expect({x: {a: 1}}).to.not.include({x: {a: 1}});// 目标对象深度(但不严格) 含有成员 `{a: 1}`
expect([{a: 1}]).to.have.deep.members([{a: 1}]);
expect([{a: 1}]).to.not.have.members([{a: 1}]);// 目标Set集深度(但不严格) 拥有键 `{a: 1}`
expect(new Set([{a: 1}])).to.have.deep.keys([{a: 1}]);
expect(new Set([{a: 1}])).to.not.have.keys([{a: 1}]);// 目标对象深度(但不严格) 拥有属性 `x: {a: 1}`
expect({x: {a: 1}}).to.have.deep.property('x', {a: 1});
expect({x: {a: 1}}).to.not.have.property('x', {a: 1});

.nested
在其后使用的.property 和 .include断言中可以使用.和括号表示法。

expect({a: {b: ['x', 'y']}}).to.have.nested.property('a.b[1]');
expect({a: {b: ['x', 'y']}}).to.nested.include({'a.b[1]': 'y'});

如果. 或者 []是属性名的一部分,可以在它们之前添加双反斜杠进行转义

expect({'.a': {'[b]': 'x'}}).to.have.nested.property('\\.a.\\[b\\]');
expect({'.a': {'[b]': 'x'}}).to.nested.include({'\\.a.\\[b\\]': 'x'});

.nested不可与.own断言连用

.own
使得其后的.property 和 .include断言中的继承属性被忽略。

Object.prototype.b = 2;expect({a: 1}).to.have.own.property('a');
expect({a: 1}).to.have.property('b');
expect({a: 1}).to.not.have.own.property('b');expect({a: 1}).to.own.include({a: 1});
expect({a: 1}).to.include({b: 2}).but.not.own.include({b: 2});

.own不可与.nested断言连用

.ordered
使得其后的.members断言需求以相同(译注:不加ordered时member断言值断言成员存在性而忽视顺序)的顺序断言其成员

expect([1, 2]).to.have.ordered.members([1, 2]).but.not.have.ordered.members([2, 1]);

当共同使用.include和.orderd时,排序开始于数组的首部。

expect([1, 2]).to.have.ordered.members([1, 2]).but.not.have.ordered.members([2, 1]);

.any
使得跟在其后的.key断言仅需求目标包含至少一个所给定的键名,它与需求目标满足所有所给键的.all断言是相反的。

expect({a: 1, b: 2}).to.not.have.any.keys('c', 'd');

.all
使得跟在其后的.key断言仅需求目标需要包含所有所给的键名,它与仅需求目标包含至少一个所给定的键名.any断言是相反的。

expect({a: 1, b: 2}).to.have.all.keys('a', 'b');

需要注意的是当all和any都没有在链式之前添加的时候是默认使用all断言的,然而最好的方式通常是显式的加上all以提高断言的可读性。

.lengthOf(n[, msg]):
断言目标的length或size与给定值相同,接受参数msg在断言错误时给出提示。其也可以与.above、.below、.most、.lease、.within等断言连用。由于兼容性问题,lengthOf的别名length不能直接链接到未经经声明的方法如.a,,因此两者不可互换,应该用lengthOf来代替length。

.lengthOf接受当断言失败时的客户错误提示参数msg
该参数也可以作为expect的第二个参数给出。

expect([1, 2, 3]).to.have.lengthOf(2, 'nooo why fail??');
expect([1, 2, 3], 'nooo why fail??').to.have.lengthOf(2);

译注:当api中含有可选参数[msg]时均指当断言失败时的客户错误提示参数msg。此时当该断言出现失败时用户提示信息可以用以下两种形式给出。
expect(target).somechain.somechain.(val, [msg]);
expect(target, [msg]).somechain.somechain.(val);
后续api中会多次出现[msg]均为可在此处传入错误信息的含义。如果该api参数中不包含[msg]参数,则说明其仅接受错误信息参数作为expect的第二个参数被给出。

.match(re[, msg]):
断言目标与给定的正则规则相匹配。

.string(str[, msg]):
断言目标字符串包含所给子串,支持message在出错时给出用户信息。

.keys(key1[, key2[, …]]):
断言目标对象、数组、map集、set集包含所给键,只有目标的自身属性在所搜索范围内。当目标是一个对象或者一个数组时,键可以以一个或者多个字符串参数的形式提供,也可以是一个单一的数组参数或这一个单独的对象参数,当是后一种情况(单独的对象参数)时,仅考虑给定对象的键素材,而忽略它的值。当目标是一个set或者map时,每一个键都必须以参数分隔的形式提供。因为.key基于不同目标类型做了不同的事,所以在使用.key之前进行类型检测是非常重要的。
默认情况下,使用严格相等的方式比较set和map键,在链式中较早添加.deep可以使用深度相等的方式去替换它。
默认情况下目标必须含有所有给出的键,可以在链式之前加入.any使得目标仅需包含至少一个给出的键。需要注意的是当.all和.any都没有添加的时候默认是使用.all的,但是推荐显示的使用.all来提高阅读性。
当.include和.any连用的时候,仅.any生效

// 以下的两种断言是不同的
expect({a: 1}).to.have.any.keys('a', 'b’);
expect({a: 1}).to.include.any.keys('a', 'b');

其错误信息仅可以作为expect的第二个参数被给出。

.throw([errorLike], [errMsgMatcher], [msg])
当没有提供参数时,.throw调用目标函数并断言有一个错误将被抛出。当有一个参数被提供,并且该参数是一个错误构造器,.throw调用目标函数并断言有一个错误被抛出,该错误是所给构造器的一个实例。
当仅提供一个参数,且该参数是一个错误实例时,.throw调用目标函数并断言其产生一个与给定错误实例严格相等的错误。
当仅提供一个字符串参数时,.throw调用目标函数并断言其产生一个包含给定字符串信息的错误。
当仅提供一个正则表达式参数时,.throw调用目标函数并断言其产生一个符合所给正则表达式信息的错误。
注意一些常见的错误:
注意传入函数由.throw进行调用,而不是自己调用

expect(fn).to.throw(); // Good! Tests `fn` as desired
expect(fn()).to.throw(); // Bad! Tests result of `fn()`, not `fn`

另一个常见问题是当目标是一个对象的方法或者是一个依赖this独立运行的函数时,由于函数被.throw调用时会丢失原有的this环境而无法得知所谓的this到底指什么。关于这个问题目前有两种方案,第一种是将方法或函数在另一个函数中调用,另一种方式是使用bind进行绑定
.throws和.Throw可以与.throw互换

.respondTo(method[, msg])
当目标是一个非函数对象时, .respondTo断言该对象包含所提供方法名称的方法,该方法可以是自身的也可以是继承的,可以是可枚举也可以时不可枚举的。
当目标是一个函数时断言该函数原型属性又一个与所给名称相同的方法。同样的,该方法可以是自身的也可以是继承的,可以是可枚举也可以时不可枚举的。

.itself
强制链中的所有断言表现得好像目标是非函数对象,即使它是一个函数。因此,它导致断言目标具有给定名称的方法,而不是断言目标的原型属性具有给定名称的方法。

.satisfy(matcher[, msg])
将目标值作为所给matcher方法的第一个参数进行调用,并断言返回值为真。

.closeTo(expected, delta[, msg])
断言目标值是一个基于期待值(expected)+/- 差值(delta)范围内的数字。

.members(set[, msg])
断言目标数组与所给数组set具有相同成员。
默认情况下是断言成员严格相等,在链式之前增加.deep可以使使用深度相等的方式替代严格相等

// Target array deeply (but not strictly) has member `{a: 1}`
expect([{a: 1}]).to.have.deep.members([{a: 1}]);
expect([{a: 1}]).to.not.have.members([{a: 1}]);

默认情况下,顺序是不进行匹配的。在链式之前添加.ordered可以使得成员匹配按照相同的顺序进行。
expect([1, 2, 3]).to.have.ordered.members([1, 2, 3]);
expect([1, 2, 3]).to.have.members([2, 1, 3]) .but.not.ordered.members([2, 1, 3]);
默认情况下,目标数组应与所给数组集保持相同size,在链式之前添加.include可以使得目标数组为期待数组的一个超集。需要注意的是在添加.include后,子集中重复的成员是会被忽略的
.deep、.include和.ordered都可以与其联合使用。值得注意的是,当链式中存在.include和.ordered时,期待数组与目标数组应该保持相同的顺序。
expect([{a: 1}, {b: 2}, {c: 3}]) .to.include.deep.ordered.members([{a: 1}, {b: 2}])
.but.not.include.deep.ordered.members([{b: 2}, {c: 3}]);

.oneOf(list[, msg])
断言目标时期待数组list的成员,但最好的方式时断言其为某个确认的值。
将会以严格相等的方式进行比较。

.change(subject[, prop[, msg]])
当一个参数被给定时。.change断言给定函数subject在目标函数之前调用和在目标函数之后调用的返回值不同。但更好的方式时断言函数会返回具体的某个值。
当有两个函数被提供时,.change断言对象subject的属性prop在目标函数调用前后的值是不同的。

.increase(subject[, prop[, msg]])
当一个参数被给定时。.increase断言给定函数subject在目标函数之后调用比在目标函数之前调用的返回值更大。但更好的方式是断言函数会增加具体的数值而不是断言他会增加任意数值。

var myObj = {val: 1}, subtractTwo = function () { myObj.val -= 2; };
expect(subtractTwo).to.decrease(myObj, 'val').by(2); // Recommended
expect(subtractTwo).to.not.increase(myObj, 'val'); // Not recommended

当有两个函数被提供时,.increase断言对象subject的属性prop在目标函数调用后比调用之前更大。

.decrease(subject[, prop[, msg]])
当一个参数被给定时。.decrease断言给定函数subject在目标函数之后调用比在目标函数之前调用的返回值更小。但更好的方式是断言函数会减少具体的数值而不是断言他会减少任意数值。

var val = 1, subtractTwo = function () { val -= 2; }, getVal = function () { return val; };expect(subtractTwo).to.decrease(getVal).by(2); // Recommended
expect(subtractTwo).to.decrease(getVal); // Not recommended

当有两个函数被提供时,.increase断言对象subject的属性prop在目标函数调用后比调用之前更小。

.by(delta[, msg])
当.by跟在.increase链式断言之后,.by断言.increase断言的增量为给定的差值(delta)。
当.by跟在.decrease链式断言之后,.by断言.decrease断言的减少量为给定的差值(delta)。
当.by跟在.change链式断言之后,.by断言.change断言的差量为给定的差值(delta)。但这样做会产生问题,因为这将会产生一个不确定的期待,通常最好的做法是确认一个精准的期待输出,而只用精确输出去断言。

var myObj = {val: 1}, addTwo = function () { myObj.val += 2; }, subtractTwo = function () { myObj.val -= 2; };expect(addTwo).to.increase(myObj, 'val').by(2); // 推荐的做法
expect(addTwo).to.change(myObj, 'val').by(2); // 不推荐的做法expect(subtractTwo).to.decrease(myObj, 'val').by(2); // 推荐的做法
expect(subtractTwo).to.change(myObj, 'val').by(2); // 不推荐的做法

.extensible
断言目标是可扩展的,这意味着可以向其添加新属性。原始值是绝对不可扩展的。在.extensible链式结构之前添加.not可以否定.extensible.

译注:对象的可拓展性用以表示是否可以给对象添加新属性。所有内置对象和自定义对象都是显示可拓展的,除非将它们转换为不可拓展的。同样,宿主对象的可拓展性也是由实现ECMAScript5的IavaScript引擎定义的。

var nonExtensibleObject = Object.preventExtensions({}), sealedObject = Object.seal({}), frozenObject = Object.freeze({});expect(nonExtensibleObject).to.not.be.extensible;
expect(sealedObject).to.not.be.extensible;
expect(frozenObject).to.not.be.extensible;
expect(1).to.not.be.extensible;

其错误信息仅可以作为expect的第二个参数被给出。

expect(1, 'nooo why fail??').to.be.extensible;

.sealed
断言目标是密封的,这意味着将无法加入新属性,并且已存在的属性无法重新配置或者删除,这也意味着已存在的属性在重新分配不同值之后仍然可能保持。原始值均是密封的。

var sealedObject = Object.seal({});
var frozenObject = Object.freeze({});expect(sealedObject).to.be.sealed;
expect(frozenObject).to.be.sealed;
expect(1).to.be.sealed;

在.sealed链式结构之前添加.not可以否定.sealed。

expect({a: 1}).to.not.be.sealed;

其错误信息仅可以作为expect的第二个参数被给出。

expect({a: 1}, 'nooo why fail??').to.be.sealed;

.frozen
断言目标是密封的,这意味着将无法加入新属性,并且已存在的属性无法被重新分配值,重新配置或者删除。原始值总是冻结的。

var frozenObject = Object.freeze({});expect(frozenObject).to.be.frozen;
expect(1).to.be.frozen;

在.frozen链式结构之前添加.not可以否定.frozen。

expect({a: 1}).to.not.be.frozen;

其错误信息仅可以作为expect的第二个参数被给出。

expect({a: 1}, 'nooo why fail??').to.be.frozen;

.finite
断言目标是一个非NaN的数字,且该数字既不是正无穷也是负无穷。

expect(1).to.be.finite;

可以在链式之前增加.not进行否定,但这样的做法是危险的,因为这将会产生一个不确定的期待,它可能不是一个数字,或者是NaN,也可能是正无穷或者负无穷。所以通常最好的做法是期待它产生一个精确的输出,然后仅仅去断言可能会产生的期待。
当目标不被期待是一个数字是最好是去断言它是某个你期待的类型,而不是断言它是许多个不符合断言的类型之一。

expect('foo').to.be.a('string'); // Recommended
expect('foo').to.not.be.finite; // Not recommended

其错误信息仅可以作为expect的第二个参数被给出。

expect('foo', 'nooo why fail??').to.be.finite;

.fail([message])
.fail(actual, expected, [message], [operator])

抛出一个错误。

expect.fail();
expect.fail("custom error message");
expect.fail(1, 2);
expect.fail(1, 2, "custom error message");
expect.fail(1, 2, "custom error message", ">");
expect.fail(1, 2, undefined, ">");

译注:当仅有一个参数传入时抛出一个错误,将所传入信息作为错误信息。当传入三个参数时,分别 传入实际值,期待的值和错误提示,并将这个错误抛出。

这篇关于单元测试断言库:chai.js中文文档的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/155502

相关文章

使用C#代码在PDF文档中添加、删除和替换图片

《使用C#代码在PDF文档中添加、删除和替换图片》在当今数字化文档处理场景中,动态操作PDF文档中的图像已成为企业级应用开发的核心需求之一,本文将介绍如何在.NET平台使用C#代码在PDF文档中添加、... 目录引言用C#添加图片到PDF文档用C#删除PDF文档中的图片用C#替换PDF文档中的图片引言在当

详解C#如何提取PDF文档中的图片

《详解C#如何提取PDF文档中的图片》提取图片可以将这些图像资源进行单独保存,方便后续在不同的项目中使用,下面我们就来看看如何使用C#通过代码从PDF文档中提取图片吧... 当 PDF 文件中包含有价值的图片,如艺术画作、设计素材、报告图表等,提取图片可以将这些图像资源进行单独保存,方便后续在不同的项目中使

用js控制视频播放进度基本示例代码

《用js控制视频播放进度基本示例代码》写前端的时候,很多的时候是需要支持要网页视频播放的功能,下面这篇文章主要给大家介绍了关于用js控制视频播放进度的相关资料,文中通过代码介绍的非常详细,需要的朋友可... 目录前言html部分:JavaScript部分:注意:总结前言在javascript中控制视频播放

Python实现合并与拆分多个PDF文档中的指定页

《Python实现合并与拆分多个PDF文档中的指定页》这篇文章主要为大家详细介绍了如何使用Python实现将多个PDF文档中的指定页合并生成新的PDF以及拆分PDF,感兴趣的小伙伴可以参考一下... 安装所需要的库pip install PyPDF2 -i https://pypi.tuna.tsingh

一文教你解决Python不支持中文路径的问题

《一文教你解决Python不支持中文路径的问题》Python是一种广泛使用的高级编程语言,然而在处理包含中文字符的文件路径时,Python有时会表现出一些不友好的行为,下面小编就来为大家介绍一下具体的... 目录问题背景解决方案1. 设置正确的文件编码2. 使用pathlib模块3. 转换路径为Unicod

Python批量调整Word文档中的字体、段落间距及格式

《Python批量调整Word文档中的字体、段落间距及格式》这篇文章主要为大家详细介绍了如何使用Python的docx库来批量处理Word文档,包括设置首行缩进、字体、字号、行间距、段落对齐方式等,需... 目录关键代码一级标题设置  正文设置完整代码运行结果最近关于批处理格式的问题我查了很多资料,但是都没

Node.js net模块的使用示例

《Node.jsnet模块的使用示例》本文主要介绍了Node.jsnet模块的使用示例,net模块支持TCP通信,处理TCP连接和数据传输,具有一定的参考价值,感兴趣的可以了解一下... 目录简介引入 net 模块核心概念TCP (传输控制协议)Socket服务器TCP 服务器创建基本服务器服务器配置选项服

mac安装nvm(node.js)多版本管理实践步骤

《mac安装nvm(node.js)多版本管理实践步骤》:本文主要介绍mac安装nvm(node.js)多版本管理的相关资料,NVM是一个用于管理多个Node.js版本的命令行工具,它允许开发者在... 目录NVM功能简介MAC安装实践一、下载nvm二、安装nvm三、安装node.js总结NVM功能简介N

Python爬虫selenium验证之中文识别点选+图片验证码案例(最新推荐)

《Python爬虫selenium验证之中文识别点选+图片验证码案例(最新推荐)》本文介绍了如何使用Python和Selenium结合ddddocr库实现图片验证码的识别和点击功能,感兴趣的朋友一起看... 目录1.获取图片2.目标识别3.背景坐标识别3.1 ddddocr3.2 打码平台4.坐标点击5.图

Python自动化Office文档处理全攻略

《Python自动化Office文档处理全攻略》在日常办公中,处理Word、Excel和PDF等Office文档是再常见不过的任务,手动操作这些文档不仅耗时耗力,还容易出错,幸运的是,Python提供... 目录一、自动化处理Word文档1. 安装python-docx库2. 读取Word文档内容3. 修改