#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.