chai-iterator:用于可迭代对象的断言
内容
概述
chai-iterator 扩展了 Chai 断言库,提供用于测试 可迭代 对象的方法。在 ES2015 规范 中引入,可迭代对象具有一个 @@iterator
方法,它允许我们使用 for...of
循环遍历它们。许多 内置 类型默认情况下是可迭代的,而 自定义可迭代对象 也可以定义。chai-iterator 使测试所有此类对象变得容易。
您可能不需要 chai-iterator
在许多情况下,数组展开运算符 是测试可迭代对象的最佳方法。然而,chai-iterator 在测试非常长(或无限)可迭代对象的一部分时非常有用。
基本用法
以下是对我们使用 Chai Iterator 可以进行的断言的相当详尽的示例。虽然我们可以很容易地使用 expect
或 assert
,但我们将使用 Chai 的 should()
断言风格,仅仅为了与众不同。
[2, 3, 5].should.be.iterable;
[2, 3, 5].should.iterate.over([2, 3, 5]);
[2, 3, 5].should.iterate.from([2, 3]);
[2, 3, 5].should.iterate.until([3, 5]);
[2, 3, 5].should.iterate.for.lengthOf(3);
[2, 3, 5].should.iterate.for.length.above(2);
[2, 3, 5].should.iterate.for.length.below(4);
[2, 3, 5].should.iterate.for.length.of.at.least(3);
[2, 3, 5].should.iterate.for.length.of.at.most(3);
[2, 3, 5].should.iterate.for.length.within(2, 4);
[2, 3, 5].should.not.iterate.over([1, 2, 3]);
[{n: 2}, {n: 3}].should.deep.iterate.from([{n: 2}]);
我们不要局限于数组;我们可以测试任何可迭代对象。
'abcde'.should.iterate.until(['c', 'd', 'e']);
我们也可以将任何可迭代对象作为我们的预期值。
'abcde'.should.iterate.until('cde');
用户定义的可迭代对象
chai-iterator 最适合用于测试 用户定义的可迭代对象,例如以下 类 所构造的对象。
class Count {
constructor(start=0, step=1) {
this.start = start;
this.step = step;
}
*[Symbol.iterator]() {
for (let n = this.start; true; n += this.step) {
yield n;
}
}
}
由 Count.prototype[@@iterator]()
生成的序列是无限的;它会无限期地继续产生值。尽管如此,我们仍然可以安全地使用 from()
断言,因为它将在我们的预期可迭代对象完成时终止。
let tens = new Count(10, 10);
tens.should.be.iterable;
tens.should.iterate.from([10, 20, 30]);
tens.should.iterate.from([10, 20, 30, 40, 50]);
只是不要尝试在无限序列上使用 over()
或 until()
。前者将始终失败,而后者将永远不会停止。
生成器和迭代器
让我们生成 斐波那契数列。一个 生成器函数 只是一个返回 Generator
对象的函数——一个既是 迭代器 又是 可迭代 的对象。我们可以像测试任何其他可迭代对象一样测试 Generator
。
function* fibonacci() {
for (let [x, y] = [1, 1]; true; [x, y] = [y, x + y]) {
yield x;
}
}
fibonacci().should.iterate.from([1, 1, 2, 3, 5]);
但要小心。迭代器不能回到过去。一旦某个值被生成,它就永远丢失了。因此,以下断言通过。
let fiborator = fibonacci();
fiborator.should.iterate.from([1, 1, 2, 3, 5]);
fiborator.should.iterate.from([8, 13, 21, 34]);
通常,为每个断言构造一个新的 Generator
更有意义。
fibonacci().should.iterate.from([1, 1, 2, 3, 5]);
fibonacci().should.iterate.from([1, 1, 2, 3, 5, 8, 13]);
兼容性
chai-iterator 要求在环境中使用 Symbol.iterator
。在 Node 中,这意味着版本必须为 v4.0 或更高版本。虽然 大多数浏览器 的最新版本是兼容的,但面向网络的项目几乎肯定应该使用 polyfill。
对于不支持 Symbol.iterator
的环境,Babel polyfill 是一个选项。更简洁的是,我们可以只从 core-js 库中获取两个子模块,如下所示。
require('core-js/es6/symbol');
require('core-js/fn/symbol/iterator');
安装
使用 npm 安装 chai-iterator。当然,还要确保安装 Chai。
npm install --save chai chai-iterator
设置
chai-iterator 可以作为 Node 模块、AMD 模块导入,或者包含在 HTML <script>
标签中。对于 TypeScript 用户,声明与包一起安装。
Node
要为 Node 设置 chai-iterator,请确保版本为 v4.0 或更高版本,因为之前的版本不支持 @@iterator
方法。
const chai = require('chai');
const chaiIterator = require('chai-iterator');
chai.use(chaiIterator);
AMD
chai-iterator 可以像这样在 AMD 模块中设置。
define((require, exports, module) => {
let chai = require('chai');
let chaiIterator = require('chai-iterator');
chai.use(chaiIterator);
});
HTML 脚本标签
chai-iterator 可以通过 <script>
标签包含。如果它在 chai.js
之后加载,Chai 将自动使用它。
<script src="chai.js"></script>
<script src="chai-iterator.js"></script>
TypeScript
TypeScript 声明包含在包中。要使用它们,请确保使用 npm 安装 chai-iterator,然后通过 typings 安装声明及其依赖项。并且一定要安装 chai 的声明。
typings install --save-dev npm~chai npm:chai-iterator
在 编译器选项 中,将 "target"
设置为 "es6"
,或者至少包含对 lib.es6.d.ts
的引用。现在以下内容将正常工作。
import chai = require("chai");
import chaiIterator = require("chai-iterator");
chai.use(chaiIterator);
[2, 3, 5].should.iterate.over([2, 3, 5]);
Expect/Should API
断言
可迭代
iterate.over()
iterate.from()
iterate.until()
iterate.for.lengthOf()
iterate.for.length.above()
iterate.for.length.below()
iterate.for.length.of.at.least()
iterate.for.length.of.at.most()
iterate.for.length.within()
可迭代
断言目标是可迭代对象,即它具有 @@iterator
方法。
expect([2, 3, 5]).to.be.iterable;
expect('abcdefg').to.be.iterable;
expect(12345).not.to.be.iterable;
iterate.over(expected)
断言目标遍历给定的值序列。设置 deep
标志以使用深度相等性来比较值。
参数 | 类型 | 描述 |
---|---|---|
expected | object |
可迭代对象。 |
expect([2, 3, 5]).to.iterate.over([2, 3, 5]);
expect('abcdefg').to.itetate.over('abcdefg');
expect([2, 3, 5]).not.to.iterate.over([2, 3]);
expect([{n: 2}, {n: 3}]).to.deep.iterate.over([{n: 2}, {n: 3}]);
iterate.from(expected)
断言目标从给定的值序列开始迭代。设置 deep
标志以使用深度相等性来比较值。
参数 | 类型 | 描述 |
---|---|---|
expected | object |
可迭代对象。 |
expect([2, 3, 5]).to.iterate.from([2, 3]);
expect('abcdefg').to.iterate.from('abc');
expect([2, 3, 5]).not.to.iterate.from([3, 5]);
expect([{n: 2}, {n: 3}]).to.deep.iterate.from([{n: 2}]);
iterate.until(expected)
断言目标以给定的值序列结束迭代。设置 deep
标志以使用深度相等性来比较值。
参数 | 类型 | 描述 |
---|---|---|
expected | object |
可迭代对象。 |
expect([2, 3, 5]).to.iterate.until([3, 5]);
expect('abcdefg').to.iterate.until('efg');
expect([2, 3, 5]).not.to.iterate.until([2, 3]);
expect([{n: 2}, {n: 3}]).to.deep.iterate.until([{n: 3}]);
iterate.for.lengthOf(n)
断言目标恰好产生 n 个值。
参数 | 类型 | 描述 |
---|---|---|
n | number |
一个正整数 |
expect([2, 3, 5]).to.iterate.for.lengthOf(3);
expect('abcdefg').to.iterate.for.lengthOf(7);
expect([2, 3, 5]).not.to.iterate.for.lengthOf(7);
iterate.for.length.above(n)
断言目标产生超过 n 个值。
参数 | 类型 | 描述 |
---|---|---|
n | number |
一个正整数 |
expect([2, 3, 5]).to.iterate.for.length.above(2);
expect('abcdefg').to.iterate.for.length.above(5);
expect([2, 3, 5]).not.to.iterate.for.length.above(3);
iterate.for.length.below(n)
断言目标产生少于 n 个值。
参数 | 类型 | 描述 |
---|---|---|
n | number |
一个正整数 |
expect([2, 3, 5]).to.iterate.for.length.below(4);
expect('abcdefg').to.iterate.for.length.below(10);
expect([2, 3, 5]).not.to.iterate.for.length.below(3);
iterate.for.length.of.at.least(n)
断言目标至少产生 n 个值。
参数 | 类型 | 描述 |
---|---|---|
n | number |
一个正整数 |
expect([2, 3, 5]).to.iterate.for.length.of.at.least(2);
expect([2, 3, 5]).to.iterate.for.length.of.at.least(3);
expect([2, 3, 5]).not.to.iterate.for.length.of.at.least(4);
iterate.for.length.of.at.most(n)
断言目标最多产生 n 个值。
参数 | 类型 | 描述 |
---|---|---|
n | number |
一个正整数 |
expect([2, 3, 5]).to.iterate.for.length.of.at.most(4);
expect([2, 3, 5]).to.iterate.for.length.of.at.most(3);
expect([2, 3, 5]).not.to.iterate.for.length.of.at.most(2);
iterate.for.length.within(min, max)
断言目标产生 min 和 max 之间的 value,包括两者。
参数 | 类型 | 描述 |
---|---|---|
min | number |
一个正整数 |
max | number |
一个正整数 |
expect([2, 3, 5]).to.iterate.for.length.within(2, 4);
expect([2, 3, 5]).to.iterate.for.length.within(3, 3);
expect([2, 3, 5]).not.to.iterate.for.length.within(4, 7);
Assert API
断言
isIterable()
isNotIterable()
iteratesOver()
doesNotIterateOver()
deepIteratesOver()
doesNotDeepIterateOver()
iteratesFrom()
doesNotIterateFrom()
deepIteratesFrom()
doesNotDeepIterateFrom()
iteratesUntil()
doesNotIterateUntil()
deepIteratesUntil()
doesNotDeepIterateUntil()
lengthOf()
参数
assert 方法的参数如下。
参数 | 类型 | 描述 |
---|---|---|
value | any |
任何值。 |
expected | object |
可迭代对象。 |
n | number |
一个正整数。 |
message? | string |
可选消息,在出错时显示。 |
isIterable(value, [message])
断言某个值是可迭代对象,即它是一个具有 @@iterator
方法的对象。
assert.isIterable([2, 3, 5]);
assert.isIterable('abcdefg');
isNotIterable(value, [message])
断言一个值不是一个可迭代对象,即它缺少一个 @@iterator
方法。
assert.isNotIterable(235);
assert.isNotIterable(true);
iteratesOver(value, expected, [message])
断言一个值精确地迭代给定的一系列值。
assert.iteratesOver([2, 3, 5], [2, 3, 5]);
assert.iteratesOver('abcdefg', 'abcdefg');
doesNotIterateOver(value, expected, [message])
断言一个值不精确地迭代给定的一系列值。
assert.doesNotIterateOver([2, 3, 5], [1, 2, 3]);
assert.doesNotIterateOver('abcdefg', 'abc');
deepIteratesOver(value, expected, [message])
断言一个值精确地迭代给定的一系列值,使用深度相等性。
assert.deepIteratesOver([{n: 2}, {n: 3}], [{n: 2}, {n: 3}]);
assert.deepIteratesOver([[0, 2], [1, 3]], [[0, 2], [1, 3]]);
doesNotDeepIterateOver(value, expected, [message])
断言一个值不精确地迭代给定的一系列值,使用深度相等性。
assert.doesNotDeepIterateOver([{n: 2}, {n: 3}], [{n: 5}, {n: 7}]);
assert.doesNotDeepIterateOver([[0, 2], [1, 3]], [[1, 3], [0, 2]]);
iteratesFrom(value, expected, [message])
断言一个值以给定的一系列值开始迭代。
assert.iteratesFrom([2, 3, 5], [2, 3, 5]);
assert.iteratesFrom([2, 3, 5], [2, 3]);
assert.iteratesFrom('abcdefg', 'abc');
assert.iteratesFrom('abcdefg', '');
doesNotIterateFrom(value, expected, [message])
断言一个值不以给定的一系列值开始迭代。
assert.doesNotIterateFrom([2, 3, 5], [3, 5]);
assert.doesNotIterateFrom('abcdefg', 'cdef');
deepIteratesFrom(value, expected, [message])
断言一个值以给定的一系列值开始迭代,使用深度相等性。
assert.deepIteratesFrom([{n: 2}, {n: 3}], [{n: 2}]);
assert.deepIteratesFrom([[0, 2], [1, 3]], [[0, 2]]);
doesNotDeepIterateFrom(value, expected, [message])
断言一个值不以给定的一系列值开始迭代,使用深度相等性。
assert.doesNotDeepIterateFrom([{n: 2}, {n: 3}], [{n: 5}]);
assert.doesNotDeepIterateFrom([[0, 2], [1, 3]], [[1, 3]]);
iteratesUntil(value, expected, [message])
断言一个值以给定的一系列值结束迭代。
assert.iteratesUntil([2, 3, 5], [2, 3, 5]);
assert.iteratesUntil([2, 3, 5], [3, 5]);
assert.iteratesUntil('abcdefg', 'efg');
assert.iteratesUntil('abcdefg', '');
doesNotIterateUntil(value, expected, [message])
断言一个值不以给定的一系列值结束迭代。
assert.doesNotIterateUntil([2, 3, 5], [2, 3]);
assert.doesNotIterateUntil('abcdefg', 'cdef');
deepIteratesUntil(value, expected, [message])
断言一个值以给定的一系列值结束迭代,使用深度相等性。
assert.deepIteratesUntil([{n: 2}, {n: 3}], [{n: 3}]);
assert.deepIteratesUntil([[0, 2], [1, 3]], [[1, 3]]);
doesNotDeepIterateUntil(value, expected, [message])
断言一个值不以给定的一系列值结束迭代,使用深度相等性。
assert.doesNotDeepIterateUntil([{n: 2}, {n: 3}], [{n: 5}]);
assert.doesNotDeepIterateUntil([[0, 2], [1, 3]], [[0, 2]]);
lengthOf(value, n, [message])
断言一个可迭代对象产生给定数量的值。如果value不是一个可迭代对象,或者它具有一个 'length'
属性,Chai 的内置 assert.lengthOf()
将被使用。
function* range(min=0, max=Infinity, step=1) {
for (let n = min; n < max; n += step) {
yield n;
}
}
assert.lengthOf(range(0, 10), 10);
assert.lengthOf(range(6, 42), 36);
许可证
版权所有 © 2016–2017 Akim McMath。根据 [MIT 许可证][license] 许可。