Как провести unit-тестирование setcookie() в php?

Однажды, я писал код для класса, который определял, какой рекламный попап показывать пользователю. Алгоритм следующий — проверяем, есть ли в браузере куки А, если такой куки нет — показываем попап, А и сохраняем куки А. Если куки, А уже установлена, проверяем сохранена ли кука Б, и либо показываем попап Б и сохраняем куку Б, либо идём проверять существование куки С и так далее. Не самое изящное, но простое решение.

Строчка за строчкой, я дошёл до места в тестах, где предстояло проверить тот факт, что куки с правильными параметрами устанавливаются у пользователя. Тогда я не смог быстро найти решение, и положился на то, что функция setcookie () сработает как надо, если предоставить ей покрытые тестами параметры.

Сегодня мне показалось, что это любопытный вопрос. Как лучше протестировать setcookie ()? Как определить юнит-тестом, что произошла установка куки? Это возможно?

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

Очевидная проблема — в режиме командной строки, который обычно используют для запуска тестов функции, связанные с заголовками ничего не делают, провести такую проверку невозможно. Но если у вас применяется веб-интерфейс, который запускает юнит-тесты через браузер, то это становится реальным. В этом случае, проверка тривиальна — создаем новый метод assertCookieSet ($params, $headers) внутри которого проверяем наличие в заголовках строчки, сформированный по спецификации, которая должна появиться после вызова setcookie ().

Правда, в этом случаем мы проверяем не факт установки куки, а то, что мы подготовили всё необходимое для браузера. Мы полагаемся на то, что браузер правильно поймёт наш заголовок и создаст куку. Получается, что в этом случае задача тоже не решена полностью — мы по-прежнему не знаем, использования нашего кода приводит к появлению куки у пользователя на компьютере или нет.

На мой взгляд, юнит тестирование не может ответить нам на этот вопрос. Помимо технических ограничений, мы пытаемся проверить сайд эффект вызова функции, которые затрагивает не столько сам класс, сколько взаимодействие между нашим кодом и браузером пользователя. Гораздо лучше вместо юнит-тестирования в этом случае написать тестирование чёрного ящика. В конечном итоге, мне нужно, чтобы попапы появлялись в нужном порядке, а не в том, ставятся куки или нет. Поэтому в этом случае лучше написать тесты для Селениума или аналогов, где мы проверим нашу функциональность.

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

Стоит отметить ещё одну опасность setcookie (). Функция возвращает true даже если куки не могут быть установлены при вызовы через php-cli. False мы получаем либо в случае провала проверки на валидность некоторых параметров, либо в случае, если сделали вывод перед вызовом setcookie (). Вот определение функции на С:

Это означает, что если использовать возврат setcookie () без учёта контекста, у нас возникнет проблема и так делать нельзя:

Если этот метод коллега использует в скрипте для командной строки, никакого сохранения не произойдёт, что приведёт к ошибке. Это возможно, если код плохо прокомментирован, коллега не просмотрел исходный код или установка куки спрятана за слоями абстракций. В этом случае необходимо проверить серверное api или бросить исключение.

Функция setcookie — http://php.net/manual/ru/function.setcookie.php
Стандарт — https://tools.ietf.org/html/rfc6265


Also published on Medium.

Добавить комментарий