为相等数组编写正确的断言测试

Writing a correct assertion test for equal arrays

我在编写正确的断言测试时遇到问题。它在单个数组上工作正常,但在测试数组数组时不起作用。问题似乎出在 areEqualItems 但我不知道为什么。我做错了什么?

function assertArraysEqual(actual, expected, testName){
    var areEqualLength = actual.length === expected.length;
    var areEqualItems = actual.every(function(item, i){
        return item === expected[i]
    });
    if(areEqualLength && areEqualItems){
        console.log('passed');
    } else {
        console.log('FALIED [' + testName + '] Expected ' + expected + ', but got ' + actual);
    }
}

var arr1 = [0,1,2,3];
var arr2 = [0,1,2,3];

var arr3 = [ [0,1,2,3], [0,1,2,3] ];
var arr4 = [ [0,1,2,3], [0,1,2,3] ];

assertArraysEqual(arr1, arr2, 'arrays should be equal'); // passed
assertArraysEqual(arr3, arr4, 'arrays should be equal'); // FALIED [arrays should be equal] Expected 0,1,2,3,0,1,2,3, but got 0,1,2,3,0,1,2,3

这里有一些关于如何使其递归的帮助:

function areArraySame(one, two) {
    var length = one.length === two.length;
    var allElems = one.every(function(item, i) {
        if (item instanceof Array) {
            return areArraySame(item, two[i]); // <-- recurse!
        }
        return item === two[i];
    });

    return length && allElems;
}

如果元素是另一个数组,则需要使其递归。

此外,当长度不匹配时,检查项目是否相等是没有意义的。

如果你把比较功能的注销也去掉就更好了。我必须以是否提供 testName 参数为条件,这样它就不会在所有递归调用期间记录。

function assertArraysEqual(actual, expected, testName) {
  var areEqualLength = actual.length === expected.length;
  var areEqualItems = areEqualLength && actual.every(function(item, i) {

    if (Array.isArray(item) && Array.isArray(expected[i])) {
      return assertArraysEqual(item, expected[i]);
    } else {
      return item === expected[i]
    }
  });
  if (testName) {
    if (areEqualItems) {
      console.log('passed');
    } else {
      console.log('FAILED [' + testName + '] Expected ' + expected + ', but got ' + actual);
    }
  }
  return areEqualItems;
}

var arr1 = [0, 1, 2, 3];
var arr2 = [0, 1, 2, 3];

var arr3 = [
  [0, 1, 2, 3],
  [0, 1, 2, 3]
];
var arr4 = [
  [0, 1, 2, 3],
  [0, 1, 2, 3]
];
var arr5 = [
  [0, 1, 2, 3],
  [0, 2, 3, 4]
];

assertArraysEqual(arr1, arr2, 'arrays should be equal'); // passed
assertArraysEqual(arr3, arr4, 'arrays should be equal'); // FALIED [arrays should be equal] Expected 0,1,2,3,0,1,2,3, but got 0,1,2,3,0,1,2,3
assertArraysEqual(arr3, arr5, 'arrays should not be equal');

将此工作交给第三方的另一种解决方案,例如 lodash。

Lodash 有 isEqual 方法可以为您完成这项工作。

查看文档 here

示例代码:

function assertArraysEqual(actual, expected, testName) {
    if (_.isEqual(actual, expected)) {
        console.log('passed');
    } else {
        console.log(`FALIED [${testName}] Expected ${expected}, but got ${actual}`);
    }
}

你可以做一个非常简洁的equals函数。只需检查长度不相等或它们不是数组的边缘情况,然后递归:

var arr3 = [[0,1,2,3], [0,1,2,3]];
var arr4 = [[0,1,2,3], [0,1,2,3]];


function equal(a, b){
  if (!Array.isArray(a) || !Array.isArray(b)) return a === b
  if (a.length !== b.length) return false

  return a.every((item, i) => equal(item, b[i]))
}

console.log(equal(arr3, arr4))
console.log(equal([[1, 2], [3, 4]], [[2, 2], [3, 4]]))

为什么不将数组字符串化然后进行比较?它会大大减少你的代码看看。

function assertArraysEqual(actual, expected) {
    const actualStr = JSON.stringify(actual);
    const expectedStr = JSON.stringify(expected);
    return actualStr === expectedStr;
}

比较数组(以及它们的子数组和它们的子数组)很快就会变得非常昂贵。此外,您编写的代码以及已接受的答案都没有考虑关联数组(又名对象)。我建议将两个数组都转换为 JSON 字符串,然后将它们作为字符串进行比较。

function assertArraysEqual(actual, expected, testName){
    if ( actual.length === expected.length && JSON.stringify(actual) == JSON.stringify(expected) ) console.log('passed');
    else console.log('FALIED [' + testName + '] Expected ' + expected + ', but got ' + actual);
}

var arr1 = [0,1,2,3];
var arr2 = [0,1,2,3];

var arr3 = [ [0,1,2,3], [0,1,2,3] ];
var arr4 = [ [0,1,2,3], [0,1,2,3] ];

assertArraysEqual(arr1, arr2, 'arrays should be equal'); 
assertArraysEqual(arr3, arr4, 'arrays should be equal');