lig*_*ght 8 javascript unit-testing qunit ecmascript-6
我们如何断言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.
Run Code Online (Sandbox Code Playgroud)
目的是断言集合/映射的元素是相等的.这两个断言都应该失败.
是否有deepEqual套装/地图的等价物?换句话说,如果没有手动迭代元素,我们如何深入测试Set/Map的平等?
如果在QUnit中没有办法,是否有适用于ES6套件和地图的单元测试工具?
编辑
在支持的Firefox中,Array.from()我一直在通过以下方式比较集合和映射:
assert.deepEqual(Array.from(m1), Array.from(m2));
Run Code Online (Sandbox Code Playgroud)
但这不适用于其他不支持的浏览器Array.from().即使使用Array.frompolyfill,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.
Run Code Online (Sandbox Code Playgroud)
更新:
补丁目前正在QUnit中进行扩展deepEqual(),以扩展到处理ES6集和地图.当拉取请求合并时,我们应该可以deepEqual()用来比较集合和地图.( - :
使用高阶函数进行详尽的地图比较
\n\n我将采用与在类似答案中处理数组比较相同的方式来处理此问题:How to Compare arrays in JavaScript?
\n\n我将一点一点地浏览代码,但最后我将有一个完整的可运行示例
\n\n浅比较
\n\n首先,我们将从通用的地图比较函数开始。这样我们就可以对 Map 对象进行各种比较,而不仅仅是测试相等性
\n\n该mapCompare函数符合我们关于如何比较 Map 的直觉 - 我们将 中的每个键m1与 中的每个键进行比较m2。请注意,该特定比较器正在进行浅比较。我们稍后将进行深度比较
const mapCompare = f => (m1, m2) => {\n const aux = (it, m2) => {\n let {value, done} = it.next()\n if (done) return true\n let [k, v] = value\n return f (v, m2.get(k), $=> aux(it, m2))\n }\n return aux(m1.entries(), m2) && aux(m2.entries(), m1)\n}\nRun Code Online (Sandbox Code Playgroud)\n\n唯一可能无法立即清楚的是$=> aux(it, m2)重击声。映射有一个内置生成器 ,.entries()我们可以利用惰性求值,false一旦发现不匹配的键/值对就返回早期答案。这意味着我们必须以稍微特殊的方式编写比较器。
const shortCircuitEqualComparator = (a, b, k) =>\n a === b ? true && k() : false\nRun Code Online (Sandbox Code Playgroud)\n\na和分别b是和的值。如果两个值严格相等 ( ),则我们才要继续比较 \xe2\x80\x93,在这种情况下,我们返回键/值对比较的剩余部分。另一方面,如果和不匹配,我们可以提前返回并跳过比较其余值 \xe2\x80\x93 即,我们已经知道和不匹配(如果有/)m1.get(somekey)m2.get(somekey)===true && k()k()abfalsem1m2 ab不匹配。
最后,我们可以定义mapEqual- 这也很简单。它只是mapCompare使用我们的特殊shortCircuitEqualComparator
const mapEqual = mapCompare (shortCircuitEqualComparator)\nRun Code Online (Sandbox Code Playgroud)\n\n让我们快速了解一下它是如何工作的
\n\n// define two maps that are equal but have keys in different order\nconst a = new Map([[\'b\', 2], [\'a\', 1]])\nconst b = new Map([[\'a\', 1], [\'b\', 2]])\n\n// define a third map that is not equal\nconst c = new Map([[\'a\', 3], [\'b\', 2]])\n\n// verify results\n// a === b should be true\n// b === a should be true\nconsole.log(\'true\', mapEqual(a, b)) // true true\nconsole.log(\'true\', mapEqual(b, a)) // true true\n\n// a === c should be false\n// c === a should be false too\nconsole.log(\'false\', mapEqual(a, c)) // false false\nconsole.log(\'false\', mapEqual(c, a)) // false false\nRun Code Online (Sandbox Code Playgroud)\n\n哎呀,是的。事情看起来不错...
\n\n与《瑞克与莫蒂》的深入比较
\n\n现在我们有了一个非常甜蜜的mapCompare通用名称,深入比较变得轻而易举。请注意,我们实际上是在mapDeepCompare使用mapCompare自身来实现。
我们使用一个自定义比较器来简单地检查 和 是否a都是bMap 对象 \xe2\x80\x93 如果是,我们mapDeepCompare在嵌套 Map 上递归使用;还要注意调用... && k()以确保比较剩余的键/值对。如果 或a是非bMap 对象,则正常比较是使用f,我们k直接传递延续
const mapDeepCompare = f => mapCompare ((a, b, k) => {\n console.log(a, b)\n if (a instanceof Map && b instanceof Map)\n return mapDeepCompare (f) (a,b) ? true && k() : false\n else\n return f(a,b,k)\n})\nRun Code Online (Sandbox Code Playgroud)\n\n现在有了mapDeepCompare,我们可以在嵌套 Map 上执行任何类型的深度比较。请记住,平等只是我们可以检查的事情之一。
无需再费周折,mapDeepEqual。重要的是,我们可以重用shortCircuitEqualComparator之前定义的内容。这非常清楚地表明我们的比较器可以(重新)用于浅层或深层地图比较。
const mapDeepEqual = mapDeepCompare (shortCircuitEqualComparator) \nRun Code Online (Sandbox Code Playgroud)\n\n让我们看看它的工作原理
\n\n// define two nested maps that are equal but have different key order\nconst e = new Map([\n [\'a\', 1],\n [\'b\', new Map([[\'c\', 2]])]\n])\n\nconst f = new Map([\n [\'b\', new Map([[\'c\', 2]])],\n [\'a\', 1]\n])\n\n// define a third nested map that is not equal\nconst g = new Map([\n [\'b\', new Map([\n [\'c\', 3] \n ])],\n [\'a\', 1]\n])\n\n// e === f should be true\n// f === e should also be true\nconsole.log(\'true\', mapDeepEqual(e, f)) // true\nconsole.log(\'true\', mapDeepEqual(f, e)) // true\n\n// e === g should be false\n// g === e should also be false\nconsole.log(\'false\', mapDeepEqual(e, g)) // false\nconsole.log(\'false\', mapDeepEqual(g, e)) // false\nRun Code Online (Sandbox Code Playgroud)\n\n好的,只是为了确定一下。mapEqual如果我们调用嵌套的 Mapse和会发生什么f?由于mapEqual进行了浅比较,我们期望结果应该是false
console.log(\'false\', mapEqual(e, f)) // false\nconsole.log(\'false\', mapEqual(f, e)) // false\nRun Code Online (Sandbox Code Playgroud)\n\n现在你就得到了它。ES6 Map 对象的浅层和深层比较。可以编写一组几乎相同的函数来支持 ES6 Set。我将把这个作为练习留给读者。
\n\n可运行代码演示
\n\n这是将上面的所有代码编译成一个可运行的演示。每次console.log调用都会输出<expected>, <actual>. 因此true, trueorfalse, false将是通过测试 \xe2\x80\x93 而true, false将是失败的测试。
const mapCompare = f => (m1, m2) => {\n const aux = (it, m2) => {\n let {value, done} = it.next()\n if (done) return true\n let [k, v] = value\n return f (v, m2.get(k), $=> aux(it, m2))\n }\n return aux(m1.entries(), m2) && aux(m2.entries(), m1)\n}\nRun Code Online (Sandbox Code Playgroud)\r\n| 归档时间: |
|
| 查看次数: |
629 次 |
| 最近记录: |