23

プログラムのテストを書いています。プログラムの出力が期待どおりであることを検証する機能テストを書きたいと思います。返されるオブジェクトは、複雑な JS オブジェクト (ネストされたオブジェクト、多くのプロパティなど) です。

これが明らかに必要なものと一致することをテストしたいと思います。これまでは、オブジェクトと期待される結果を「閲覧」し、各プロパティとネストされた各オブジェクトをチェックしていました。これは非常に面倒で、オブジェクトだけに基づいてすべてのテストを「ビルド」するライブラリがあるかどうか疑問に思っていました。たとえば、このようなもの。

var res = {
  a: {
    alpha: [1,2,3],
    beta: "Hello",
    gamma: "World"
    },
    },
    b: 123,
    c: "It depends"
  }
};
var expectation = {
  a: {
    alpha: [1,2,4],
    beta: "Hello",
    gamma: "World"
    },
    },
    b: 123,
    c: "It depends"
  }
};

assert(res, expectation) // -> Raises an error because res[a][b][2] is different from expectation[a][b][2].

[例では、オブジェクトの複雑さを単純化しています...]

2 つのオブジェクトが異なることを伝えるだけでなく、何が違うのかを伝えるのに十分なほどスマートなコードが必要であるという事実を主張する必要があります。私たちは今、深い平等について考えていますが、実際に違いを教えてくれるものは何も見つけていません。

4

6 に答える 6

24

ノードには、テスト用のassertモジュールが組み込まれています。これには、深い等値チェック用のdeepEqualというメソッドがあります。

関数のシグネチャは次のとおりです。

assert.deepEqual(actual, expected, [message])

deepEquality をテストして diff を返すための簡単に記述された関数:

// Will test own properties only
function deepEqualWithDiff(a, e, names){
  var dif = {};
  var aKeys = Object.keys(a);
  var eKeys = Object.keys(e);

  var cKeys = aKeys;
  var dKeys = eKeys;
  var c = a;
  var d = e;
  var names = {
    c: names ? names['a'] : 'Actual',
    d: names ? names['e'] : 'Expected'
  }

  if(eKeys.length > aKeys.length){
    cKeys = eKeys;
    dKeys = aKeys;
    c = e;
    d = a;
    names = {
      d: names ? names['a'] : 'Actual',
      c: names ? names['e'] : 'Expected'
    }
  }


  for(var i = 0, co = cKeys.length; i < co; i++){
    var key = cKeys[i];
    if(typeof c[key] !== typeof d[key]){
      dif[key] = 'Type mismatch ' + names['c'] + ':' + typeof c[key] + '!==' + names['d'] + typeof d[key];
      continue;
    }
    if(typeof c[key] === 'function'){
      if(c[key].toString() !== d[key].toString()){
        dif[key] = 'Differing functions';
      }
      continue;
    }
    if(typeof c[key] === 'object'){
      if(c[key].length !== undefined){ // array
        var temp = c[key].slice(0);
        temp = temp.filter(function(el){
          return (d[key].indexOf(el) === -1);
        });
        var message = '';
        if(temp.length > 0){
          message += names['c'] + ' excess ' + JSON.stringify(temp);
        }

        temp = d[key].slice(0);
        temp = temp.filter(function(el){
          return (c[key].indexOf(el) === -1);
        });
        if(temp.length > 0){
          message += ' and ' + names['d'] + ' excess ' + JSON.stringify(temp);
        }
        if(message !== ''){
          dif[key] = message;
        }
        continue;
      }
      var diff = deepEqualWithDiff(c[key], d[key], {a:names['c'],e:names['d']});
      if(diff !== true && Object.keys(diff).length > 0){
        dif[key] = diff;
      }
      continue;
    }
    // Simple types left so
    if(c[key] !== d[key]){
      dif[key] = names['c'] + ':' + c[key] + ' !== ' + names['d'] + ':' + d[key]; 
    }
  }
  return Object.keys(dif).length > 0 ? dif : true;
}
于 2012-09-27T21:20:36.353 に答える
17

JavaScript はそのままではオブジェクトの深い等価性をサポートしておらず、NodeJS API に組み込まれているものについても認識していません。

私の賭けは、おそらくUnderscoreisEqual関数でしょう。

npm install アンダースコア

var _ = require('underscore');
var moe   = {name : 'moe', luckyNumbers : [13, 27, 34]};
var clone = {name : 'moe', luckyNumbers : [13, 27, 34]};
moe == clone;
=> false
_.isEqual(moe, clone);
=> true

ほとんどのノード テスト フレームワークには、オブジェクトの深い等価性アサーションも含まれている必要がありますが、使用しているアサーションについては言及していません。

于 2012-09-27T21:07:23.397 に答える
0

これは、Lodash を使用して作成したシンプルで柔軟な深層差分関数です。

_.merge(obj1, obj2, function (objectValue, sourceValue, key, object, source) {
    if ( !(_.isEqual(objectValue, sourceValue)) && (Object(objectValue) !== objectValue)) {
        console.log(key + "\n    Expected: " + sourceValue + "\n    Actual: " + objectValue);
    }
});

console.log()ステートメントは、必要な比較ロジックに置き換えることができます。私は違いをコンソールに出力するだけです。

于 2015-06-23T18:22:32.047 に答える