使用 QUnit(或其他单元测试工具)测试映射/集
Testing Maps/Sets with QUnit (or other Unit Testing Tool)
我们如何断言 ES6 地图和集合的相等性?
例如:
// ES6 Map
var m1 = new Map();
m1.set('one', 1);
var m2 = new Map();
m2.set('two', 2);
assert.deepEqual(m1,m2); // outputs: passed.
// ES6 Set
var s1 = new Set();
s1.add(1);
var s2 = new Set();
s2.add(2);
assert.deepEqual(s1,s2); // outputs: passed.
目的是断言集合/映射的元素是相等的。这两个断言都应该失败。
集合/地图是否有等效的deepEqual
?换句话说,除了手动迭代元素之外,我们如何深入测试 Set/Map 相等性?
如果在 QUnit 中没有办法,是否有适用于 ES6 集和地图的单元测试工具?
编辑
在支持Array.from()
的Firefox中,我一直通过以下方式比较集合和映射:
assert.deepEqual(Array.from(m1), Array.from(m2));
但这不适用于其他浏览器,这些浏览器不支持 Array.from()
.即使使用Array.from
的 polyfill,Chrome/IE 也无法正常工作 - 无论设置的内容如何,Array.from(set)
总是生成一个空数组。这可能是由于这些浏览器缺乏对通用可迭代对象的支持。
其次,将其简化为数组的比较可能并不总是合适的。我们最终会得到我认为是误报的情况:
var s = new Set();
s.add([1,2]);
var m = new Map();
m.set(1,2);
assert.deepEqual(Array.from(s), Array.from(m)); // outputs: passed.
更新:
QUnit目前正在开发一个补丁,以扩展deepEqual()
以处理ES6集和地图。当拉取请求被合并时,我们应该能够使用 deepEqual()
来比较集合和映射。(-:
使用高阶函数进行详尽的映射比较
我将以与在这个类似答案中处理数组比较相同的方式来处理这个问题:如何在 JavaScript 中比较数组?
我将逐位浏览代码,但最后我将提供一个完整的可运行示例
浅层比较
首先,我们将从一个通用的 Map 比较函数开始。通过这种方式,我们可以对 Map 对象进行各种比较,而不仅仅是测试相等性
这个mapCompare
函数符合我们关于如何比较地图的直觉——我们将m1
中的每个键与m2
中的每个键进行比较。请注意,此特定比较器正在进行浅层比较。我们将在一会儿处理深度比较
const mapCompare = f => (m1, m2) => {
const aux = (it, m2) => {
let {value, done} = it.next()
if (done) return true
let [k, v] = value
return f (v, m2.get(k), $=> aux(it, m2))
}
return aux(m1.entries(), m2) && aux(m2.entries(), m1)
}
唯一可能不是立即清楚的是$=> aux(it, m2)
的笨蛋。映射有一个内置的生成器, .entries()
,我们可以利用惰性求值,一旦找到不匹配的键/值对,就返回早期false
答案。这意味着我们必须以一种稍微特殊的方式来编写我们的比较器。
const shortCircuitEqualComparator = (a, b, k) =>
a === b ? true && k() : false
a
和b
分别是m1.get(somekey)
和m2.get(somekey)
的值。如果两个值严格相等(===
(,只有这样我们才想继续比较——在这种情况下,我们返回true && k()
其中k()
是键/值对比较的其余部分。另一方面,如果a
和b
不匹配,我们可以返回早期false
并跳过比较其余值——即,我们已经知道,如果任何a
/b
对不匹配,m1
和m2
不匹配。
最后,我们可以定义mapEqual
- 它也很简单。这只是使用我们的特殊shortCircuitEqualComparator
mapCompare
const mapEqual = mapCompare (shortCircuitEqualComparator)
让我们快速看一下它是如何工作的
// define two maps that are equal but have keys in different order
const a = new Map([['b', 2], ['a', 1]])
const b = new Map([['a', 1], ['b', 2]])
// define a third map that is not equal
const c = new Map([['a', 3], ['b', 2]])
// verify results
// a === b should be true
// b === a should be true
console.log('true', mapEqual(a, b)) // true true
console.log('true', mapEqual(b, a)) // true true
// a === c should be false
// c === a should be false too
console.log('false', mapEqual(a, c)) // false false
console.log('false', mapEqual(c, a)) // false false
哎呀是的。事情看起来不错...
与瑞克和莫蒂的深度比较
现在我们有了mapCompare
通用的甜蜜,深度比较是轻而易举的。请注意,我们实际上是使用 mapCompare
本身来实现mapDeepCompare
。
我们使用自定义比较器,它只是检查a
和b
是否都是 Map 对象——如果是,我们在嵌套的 Map 上使用mapDeepCompare
递归;还要注意调用... && k()
以确保比较剩余的键/值对。如果a
或b
是非 Map 对象,则正常比较是使用 f
进行的,我们直接传递延续k
const mapDeepCompare = f => mapCompare ((a, b, k) => {
console.log(a, b)
if (a instanceof Map && b instanceof Map)
return mapDeepCompare (f) (a,b) ? true && k() : false
else
return f(a,b,k)
})
现在有了 mapDeepCompare
,我们可以在嵌套地图上执行任何类型的深度比较。请记住,平等只是我们可以检查的事情之一。
事不宜迟,mapDeepEqual
.重要的是,我们可以重用我们之前定义的shortCircuitEqualComparator
。这非常清楚地表明,我们的比较器可以(重新(用于浅图或深图比较。
const mapDeepEqual = mapDeepCompare (shortCircuitEqualComparator)
让我们看看它的工作原理
// define two nested maps that are equal but have different key order
const e = new Map([
['a', 1],
['b', new Map([['c', 2]])]
])
const f = new Map([
['b', new Map([['c', 2]])],
['a', 1]
])
// define a third nested map that is not equal
const g = new Map([
['b', new Map([
['c', 3]
])],
['a', 1]
])
// e === f should be true
// f === e should also be true
console.log('true', mapDeepEqual(e, f)) // true
console.log('true', mapDeepEqual(f, e)) // true
// e === g should be false
// g === e should also be false
console.log('false', mapDeepEqual(e, g)) // false
console.log('false', mapDeepEqual(g, e)) // false
好的,只是为了确定。如果我们在嵌套的地图上调用mapEqual
e
和f
会发生什么?由于mapEqual
进行了浅层比较,因此我们预计结果应该是false
console.log('false', mapEqual(e, f)) // false
console.log('false', mapEqual(f, e)) // false
你有它。ES6 Map 对象的浅层和深度比较。可以编写一组几乎相同的函数来支持 ES6 Set。我将把这作为读者的练习。
可运行代码演示
这是上面编译成单个可运行演示的所有代码。每个console.log
调用输出<expected>, <actual>
。因此,true, true
或false, false
将是一个及格的测试,而true, false
将是一个失败的测试。
// mapCompare :: ((a, a, (* -> Bool)) -> Bool) -> (Map(k:a), Map(k:a)) -> Bool
const mapCompare = f => (m1, m2) => {
const aux = (it, m2) => {
let {value, done} = it.next()
if (done) return true
let [k, v] = value
return f (v, m2.get(k), $=> aux(it, m2))
}
return aux(m1.entries(), m2) && aux(m2.entries(), m1)
}
// mapDeepCompare :: ((a, a, (* -> Bool)) -> Bool) -> (Map(k:a), Map(k:a)) -> Bool
const mapDeepCompare = f => mapCompare ((a, b, k) => {
if (a instanceof Map && b instanceof Map)
return mapDeepCompare (f) (a,b) ? true && k() : false
else
return f(a,b,k)
})
// shortCircuitEqualComparator :: (a, a, (* -> Bool)) -> Bool
const shortCircuitEqualComparator = (a, b, k) =>
a === b ? true && k() : false
// mapEqual :: (Map(k:a), Map(k:a)) -> Bool
const mapEqual = mapCompare (shortCircuitEqualComparator)
// mapDeepEqual :: (Map(k:a), Map(k:a)) -> Bool
const mapDeepEqual = mapDeepCompare (shortCircuitEqualComparator)
// fixtures
const a = new Map([['b', 2], ['a', 1]])
const b = new Map([['a', 1], ['b', 2]])
const c = new Map([['a', 3], ['b', 2]])
const d = new Map([['a', 1], ['c', 2]])
const e = new Map([['a', 1], ['b', new Map([['c', 2]])]])
const f = new Map([['b', new Map([['c', 2]])], ['a', 1]])
const g = new Map([['b', new Map([['c', 3]])], ['a', 1]])
// shallow comparison of two equal maps
console.log('true', mapEqual(a, b))
console.log('true', mapEqual(b, a))
// shallow comparison of two non-equal maps (differing values)
console.log('false', mapEqual(a, c))
console.log('false', mapEqual(c, a))
// shallow comparison of two other non-equal maps (differing keys)
console.log('false', mapEqual(a, d))
console.log('false', mapEqual(d, a))
// deep comparison of two equal nested maps
console.log('true', mapDeepEqual(e, f))
console.log('true', mapDeepEqual(f, e))
// deep comparison of two non-equal nested maps
console.log('false', mapDeepEqual(e, g))
console.log('false', mapDeepEqual(g, e))
// shallow comparison of two equal nested maps
console.log('false', mapEqual(e, f))
console.log('false', mapEqual(f, e))
我刚刚创建了一个库(@nodeguy/断言(来解决这个问题:
const assert = require('@nodeguy/assert')
// ES6 Map
var m1 = new Map();
m1.set('one', 1);
var m2 = new Map();
m2.set('two', 2);
assert.deepEqual(m1,m2); // outputs: failed.
// ES6 Set
var s1 = new Set();
s1.add(1);
var s2 = new Set();
s2.add(2);
assert.deepEqual(s1,s2); // outputs: failed.
- 如何在映射数组中添加换行符
- 模糊事件的Javascript测试
- 我的单元测试选项是什么
- ng映射方向备选方案
- 无法通过数组映射绑定
- 测试索引值是否等于某个数字的倍数
- ReactJS映射:如何仅在url变量不为空时呈现html链接
- 在localhost Dev Box上测试JSONP请求的最佳方式
- 测试数组中每个项的内容
- 测试Angular Service解决错误回调中的promise
- 使用Scala Play Framework视图中的键检索映射值
- 使用Jest测试React Native应用程序
- 为函数代码编写测试
- 如何在Angular单元测试中从另一个控制器的rootScope将方法添加到rootScope中
- 如何使用JS/nightwatchjs并行运行多个测试
- 使用量角器的当前url单元测试的getTitle
- 茉莉花宝石-耙茉莉花:ci dons't运行测试
- 如何在 JSON 字符串中选择两个测试对象并将它们映射到我的接口
- 这里为JavaScript测试Bug映射API
- 使用 QUnit(或其他单元测试工具)测试映射/集