Проверьте, не изменилось ли какое-либо состояние

#javascript

Вопрос:

Я пытаюсь написать модульный тест для своей функции no-op (в шутку).

Тест должен проверить, что функция действительно ничего не сделала, что может включать или не включать следующее:

  • Выполнение вычислений
  • Изменение значений глобальных переменных (изменение глобального состояния)
  • Изменение содержимого DOM ()

Вероятно, нет никакого способа проверить, выполняет ли функция какие-либо вычисления (поскольку некоторые из них могут быть отброшены и не иметь побочных эффектов). Поэтому я хотел бы знать, есть ли способ проверить, изменилось ли какое-либо глобальное состояние.

Комментарии:

1. Это звучит как очень трудоемкая вычислительная задача. Моим первым побуждением было бы сделать копию window перед выполнением функции, а затем тщательно проверить каждую пару ключей и значений в скопированном окне на соответствие фактическому объекту окна. Для изменения DOM вы можете снова скопировать innerHTML в переменную и сверить сохраненный innerHTML с активным innerHTML.

2. Вам придется сохранить состояние до и после и сравнить каждую глобальную переменную, чтобы проверить это вручную. Все функции могут изменить глобальное состояние, если вы будете относиться к ним как к черному ящику. Вам также нужно будет убедиться, что он ничего не изменил в файлах cookie, локальном хранилище, базах данных WebSQL..

3. @David заранее Я вижу одну проблему с этим подходом-для копирования состояния нам нужна переменная для хранения копии, это само по себе изменяет глобальное состояние, что делает первоначальную реализацию неправильной. Есть ли способ создать переменную, которая не является глобальной в javascript?

4. Похоже, что при использовании тела лямбда-функции фактически используется ее собственное пространство имен.

5. Переменные, определенные const и let доступные только по их именам, а не через объект окна

Ответ №1:

Это довольно нелепый тест, и его невозможно выполнить на 100%.

Это все равно что сказать: «Из-за того, что моя функция не завела мою машину, не только машина не должна была измениться, но и весь мир вокруг нее не должен был измениться».

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

В любом случае, если вы все еще хотите это сделать, вы можете сравнить представление JSON «до и после» объекта, которое не должно было быть изменено. Для работы с круговыми ссылками вы можете использовать плоские, как показано ниже:

 function noOp(obj) {
  // DO NOTHING
};

function startCar(obj) {
  obj.started = true;
};

function test(fn) {
  const car = { id: 1, started: false };
  car.nestedCar = car;
  
  const jsonBefore = Flatted.stringify(car);
  fn(car);
  const jsonAfter = Flatted.stringify(car);
  
  console.log("Did function '"   fn.name   "' leave the car unchanged: "   (jsonBefore === jsonAfter))
}

test(noOp);
test(startCar); 
 <script src="https://unpkg.com/flatted@3.2.2/min.js"></script> 

Комментарии:

1. Я не понял сравнения, но в моем случае машина- это целый мир. Функция не должна ничего менять, в этом вся причина ее существования. Является ли такой тест нелепым — это другой вопрос, с которым я бы согласился, это так. Но в то же время я хочу знать

2. Если автомобиль-это весь мир, то вы могли бы сравнить выходные JSON.stringify(car) данные до и после запуска функции no-op.

3. к сожалению, JSON.stringify не работает с автомобилями, которые содержат сами себя.

4. Я обновил ответ, чтобы показать способ его тестирования с помощью Flatted.