Часто разделяют автоматизированные тесты веб-приложений на 4 вида (это не касаясь нагрузочных, юзабилити и т. п.):
— приёмочные — проверяют конечный результат, как правило в браузере, то есть что непосредственно знает браузер (и как следствие показывает пользователю), получая html/js/css с сервера со всеми заголовками и т. п., проверяется не только приложение (php-код), но и сервер, и браузер (например JS-код) и прочая среда. Выполняются долго. Запускаются редко.
— функциональные — проверяют почти то же самое, но на более низком уровне, сервер и браузер уже не используются обычно, а проверяется вывод скрипта, то есть что html код соответствует ожидаемому, что в базу внесены нужные изменения и т. п. Зачастую используют эмуляторы браузеров. Выполняются быстрее. Запускаются чаще.
— интеграционные — опускаются ещё ниже, проверяется взаимодействие отдельных слоев приложения, например, что роутер, получив URL (или URI? вечно их путаю), вызовет контроллер с нужными параметрами и что контроллер, получив параметры передаст в шаблон нужные переменные (тесты роутера и тесты контроллера — обычно два разных теста). Выполняются относительно быстро, запускаются часто.
— модульные (юнит) — самый низкий уровень, тестирование отдельных методов, тупо что метод с параметрами возвращает нужное значение. Выполняются очень быстро, запускаются также часто, как нажимается кнопка save или run. В идеале автоматически при её нажатии :)
На самом деле разделение довольно условно и зачастую сложно однозначно отнести конкретный тест к одному из слоев (из-за лени разработчиков :) ) — он может быть, например, как и модульный с одной стороны (проверяем вывод в ответ на ввод), так и интеграционный с другой (вывод заключается в вызове другого метода с зависящими от входных параметров). На PHPunit в принципе их писать можно, но ни разу не видел такого.
По хорошему надо тестировать всё, но, скажем, приёмочные тесты отнимают довольно много времени и если нет отдельных тестировщиков, то ими часто пренебрегают (особенно если сложного JS на клиенте нет). Функциональные дают чуть меньшую уверенность в том, что приложение работает как ожидалось, но отнимают относительно мало времени, по сути один тест является спецификацией одной ветки выполнения, то есть переписыванием ТЗ с человеческого языка на алгоритмический в терминах приложения и ЯП. Интеграционные при желании оттестировать всё что можно занимают много времени и часто являются детализацией функциональных, разбивая их на несколько частей, что несколько снижает энтузиазм их написания («это же уже работает!»). Модульные пишутся просто (если архитектура нормальная) и быстро. Если считать функциональные спецификацией приложения, то модульные это спецификация методов, с хорошей архитектурой метод многого делать не должен и спецификации примитивны.
Внутреннему заказчику я бы посоветовал (особенно при работе с существующим приложением без тестов) для начала заказать, чтобы исполнители начинали с функциональных тестов (на новую функциональность или на ту, которую нужно изменить), как минимум для основной ветки выполнения (обычный сценарии работы) и использовали модульные в нетривиальных случаях, когда функциональными добраться до неосновной ветки выполнения сложно и/или долго (например для ситуаций типа «нет места на диске» или «сервер БД недоступен»). При обнаружении бага прежде чем искать его (особенно если сходу не понятно где он конкретно), сначала написать тест, который с этим багом заваливается, а без него должен пройти. При небольшом рефакторинге (типа выделения метода-объекта) писать модульные и интеграционные (если не сложно, а сложно быть не должно) тесты.
— приёмочные — проверяют конечный результат, как правило в браузере, то есть что непосредственно знает браузер (и как следствие показывает пользователю), получая html/js/css с сервера со всеми заголовками и т. п., проверяется не только приложение (php-код), но и сервер, и браузер (например JS-код) и прочая среда. Выполняются долго. Запускаются редко.
— функциональные — проверяют почти то же самое, но на более низком уровне, сервер и браузер уже не используются обычно, а проверяется вывод скрипта, то есть что html код соответствует ожидаемому, что в базу внесены нужные изменения и т. п. Зачастую используют эмуляторы браузеров. Выполняются быстрее. Запускаются чаще.
— интеграционные — опускаются ещё ниже, проверяется взаимодействие отдельных слоев приложения, например, что роутер, получив URL (или URI? вечно их путаю), вызовет контроллер с нужными параметрами и что контроллер, получив параметры передаст в шаблон нужные переменные (тесты роутера и тесты контроллера — обычно два разных теста). Выполняются относительно быстро, запускаются часто.
— модульные (юнит) — самый низкий уровень, тестирование отдельных методов, тупо что метод с параметрами возвращает нужное значение. Выполняются очень быстро, запускаются также часто, как нажимается кнопка save или run. В идеале автоматически при её нажатии :)
На самом деле разделение довольно условно и зачастую сложно однозначно отнести конкретный тест к одному из слоев (из-за лени разработчиков :) ) — он может быть, например, как и модульный с одной стороны (проверяем вывод в ответ на ввод), так и интеграционный с другой (вывод заключается в вызове другого метода с зависящими от входных параметров). На PHPunit в принципе их писать можно, но ни разу не видел такого.
По хорошему надо тестировать всё, но, скажем, приёмочные тесты отнимают довольно много времени и если нет отдельных тестировщиков, то ими часто пренебрегают (особенно если сложного JS на клиенте нет). Функциональные дают чуть меньшую уверенность в том, что приложение работает как ожидалось, но отнимают относительно мало времени, по сути один тест является спецификацией одной ветки выполнения, то есть переписыванием ТЗ с человеческого языка на алгоритмический в терминах приложения и ЯП. Интеграционные при желании оттестировать всё что можно занимают много времени и часто являются детализацией функциональных, разбивая их на несколько частей, что несколько снижает энтузиазм их написания («это же уже работает!»). Модульные пишутся просто (если архитектура нормальная) и быстро. Если считать функциональные спецификацией приложения, то модульные это спецификация методов, с хорошей архитектурой метод многого делать не должен и спецификации примитивны.
Внутреннему заказчику я бы посоветовал (особенно при работе с существующим приложением без тестов) для начала заказать, чтобы исполнители начинали с функциональных тестов (на новую функциональность или на ту, которую нужно изменить), как минимум для основной ветки выполнения (обычный сценарии работы) и использовали модульные в нетривиальных случаях, когда функциональными добраться до неосновной ветки выполнения сложно и/или долго (например для ситуаций типа «нет места на диске» или «сервер БД недоступен»). При обнаружении бага прежде чем искать его (особенно если сходу не понятно где он конкретно), сначала написать тест, который с этим багом заваливается, а без него должен пройти. При небольшом рефакторинге (типа выделения метода-объекта) писать модульные и интеграционные (если не сложно, а сложно быть не должно) тесты.
Комментариев нет:
Отправить комментарий