Подтвердить что ты не робот

Тестирование объектов в NodeJS

Мы пишем тесты для программы. Мы хотим написать функциональный тест, который проверяет, что вывод программы соответствует некоторому ожиданию. Возвращаемый объект представляет собой сложный объект 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].

[В этом примере я упростил сложность нашего объекта...]

Я должен настаивать на том, что нам нужен фрагмент кода, который достаточно умен, чтобы рассказать нам, что отличает, а не просто сказать нам, что два объекта разные. Теперь мы о глубоком равенстве, но мы ничего не нашли, что на самом деле говорит о различиях.

4b9b3361

Ответ 1

Node имеет встроенный модуль assert, предназначенный для тестирования. Это метод, называемый deepEqual для глубокой проверки равенства.

Функциональная подпись:

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

Быстро написанная функция для проверки глубины и возврата 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;
}

Ответ 2

JavaScript не поддерживает глубокое равенство объектов из коробки, и я также не знаю ничего, встроенного в NodeJS API.

Моя ставка, вероятно, будет Underscore и isEqual.

npm установить подчеркивание

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

Хотя большинство Node модулей тестирования должны также содержать утверждение о глубоком равенстве объекта, но вы не указали, какой из них вы используете.

Ответ 3

deep-diff делает то, что просит ОП. Он может сравнивать два объекта javascript/объекты JSON и перечислять различия в способе доступа к вашему коду.

Это старый вопрос, поэтому эта библиотека, вероятно, не существовала в тот момент, когда был задан вопрос.

Ответ 4

Хотя я думаю, что основы сравнения объектов уже были рассмотрены (см. здесь и другие), если вы ищете быстрый и грязный способ выполнить эти тесты и увидеть разницу между двумя не равными объектами, вы можете просто запустить свои тесты с помощью nodeunit в среде Webstorm IDE (здесь)

Webstorm особенно хорошо интегрируется с nodeunit, а для любых утверждений test.equals() или test.deepEquals() он предоставляет видимый diff с подсветкой, чтобы показывать ваши убытки. Я настоятельно рекомендую IDE для того, насколько хорошо он интегрирует тестирование в мой цикл разработки js.

Теперь, если вам нужно, чтобы результаты этого теста /diff были доступны в вашем коде, этого явно недостаточно для вас, и я бы рекомендовал скопировать пару компараторов deepEquals из первой ссылки, которую я перечислил.

Удачи,

Брайан

Ответ 5

Это простая/гибкая функция глубокого разграничения, которую я написал с помощью 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);
    }
});