Как сделать тестирование на php
Простой инструмент для тестирования PHP приложений
Для кого эта статья
Скорее всего для тех, кто ещё не начал тестировать, но имеет такое желание. Опытных в этом деле разработчиков удивить не получится, но тех кто ещё не перешел на сторону света, попробую подтолкнуть на этот шаг.
Предыстория
Решил разобраться с автоматическим тестированием. Раньше этого делать не приходилось, да и тогда не было особо нужно. Зато было свободное время, которое решил потратить с пользой на будущее.
Почитав теорию, начал искать инструмент для этого. Предсказуемо первым на горизонте показался PhpUnit. Но он показался каким-то громоздким, что ли.
Более удобным показался Codeception — разные виды тестов, выразительный синтаксис. Но, посмотрев зависимости, я понял, что мне столько всего не нужно.
Двигаясь в сторону простоты, я нашел atoum, а потом вообще классную вещь под названием Testify.php. Тут-то я подумал, что наконец нашел то, что мне нужно.
Но я рано радовался. Testify.php не подошел при написании первого же теста. Тестировался класс кэширования, который в зависимости от того, включена отладка или нет, мог обрабатывать или игнорировать вызовы. Так как режим отладки предполагал наличие константы DEBUG со значением true/false — переопределить её в одном процессе не получится.
Требования
Реализация
Был написан небольшой скрипт, который открывал тесты по http, собирал результаты, и выдавал в презентабельном HTML виде. Для того, чтобы сделать аналогичным процесс тестирования и для консольного варианта — было решено использовать встроенный в PHP 5.4+ веб-сервер. Запускается он так:
И оно заработало как положено. Так, как аналогичного инструмента не нашел — решил оформить в виде самостоятельного composer пакета, добавил интерактивности (прогресс выполнения наборов тестов отображается в реальном времени как в HTML, так и в консольном варианте).
Теперь этот файл можно открыть либо в браузере, либо в консоли
Сами тесты не на много сложнее:
То есть, каждый отдельный тест являет собой файл, который возвращает 0 после успешного тестирования или текст ошибки, если она возникла.
Пример результата консольного варианта:
Есть возможность выполнить общие команды как перед всеми наборами тестов, так и перед всеми тестами одного набора.
PHPUnit. «Как мне протестировать мой чёртов контроллер», или тестирование для сомневающихся
Да, это очередной пост на тему тестирования. Казалось бы, что тут уже можно обсуждать? Все кому надо — пишут тесты, кому не надо — не пишут, все счастливы! Факт же в том, что большинство постов о юнит-тестировании имеют… как бы так никого не обидеть… идиотские примеры! Нет, ну правда! Сегодня я попытаюсь это исправить. Прошу под кат.
И так, быстрый гуглёж на тему тестов находит просто уйму статей, которые в своей основной массе делятся на две категории:
1) Счастье копирайтера. Сначала мы видим долгое вступление, потом историю юнит-тестирования на Древней Руси, потом десять лайфхаков с тестами, и в конце-концов пример. С тестированием кода вроде этого:
И я сейчас не шучу. Я правда видел статьи с «калькулятором» в роли учебного пособия. Да-да, я понимаю что для начала надо всё упростить, абстракции, туда-сюда… Но ведь на этом всё и заканчивается! А дальше дорисуйте сову, как говорится
2) Чрезмерно переусложнённые примеры. А давайте напишем тест, и запихнём его в Gitlab CI, а потом будем ещё автодеплоить если тест прошёл, а на тесты ещё PHP Infection намажем, да с Hudson всё соеденим. И так далее в таком стиле. Вроде и полезно, а вроде и совсем не то что ты ищешь. А ведь хочется просто чуток увеличить стабильность своего проекта. А все эти непрерывности — ну потом, не всё же сразу.
В итоге люди сомневаются, «а надо ли оно мне». Я же, в свою очередь, хочу попытаться рассказать о тестировании понятнее. И оговорюсь сразу — я разработчик, я не тестировщик. Я уверен, что я сам многого не знаю, а моим первым в жизни словом не было слово «мок». Я даже никогда не работал по TDD! Зато я точно знаю, что даже мой текущий уровень навыков позволил мне покрыть несколько проектов тестами, а эти самые тесты уже отловили свой десяток багов. А если мне это помогло — значит и кому-то ещё может помочь. Некоторые пойманные баги было бы сложно выловить вручную.
Для начала, краткий ликбез в формате вопрос-ответ:
Q: Я обязан использовать какой-то фреймворк? А что если у меня Yii? А если Kohana? А если %one_more_framework_name%?
А: Нет, PHPUnit это самостоятельный фреймворк для тестирования, вы можете его прикрутить хоть к легаси-коду на самопальном фреймворке.
Q: А я сейчас руками сайт по-быстрому прохожу, и нормально. Зачем оно мне?
А: «Прогон» нескольких десятков тестов длится несколько секунд. Автоматическое тестирование всегда быстрее мануального, а при качественных тестах ещё и надёжнее, так как покрывает все сценарии.
Q: У меня легаси-код с функциями по 2000 строк. Я могу это тестировать?
A: И да, и нет. В теории — да, любой код можно покрыть тестом. На практике, код должен писаться с заделом под будущее тестирование. Функция на 2000 строк будет иметь слишком много зависимостей, ветвлений, пограничных случаев. Может и получится её в итоге всю покрыть, но скорее всего это займёт у вас непозволительно много времени. Чем качественнее код — тем легче его тестировать. Чем лучше соблюдается принцип Single Responsibility — тем проще будут тесты. Для тестирования старых проектов чаще всего придётся сначала здорово отрефакторить их.
Q: У меня очень простые методы (функции), что там тестировать? Там всё надёжно, там нет места ошибке!
А: Следует понимать, вы не тестируете правильность реализации функции (если у вас не TDD), вы просто «фиксируете» её текущее состояние работы. В будущем, когда вам понадобится её изменять, вы сможете с помощью теста быстро определять не сломали ли вы её поведение. Пример: есть функция, которая валидирует email. Делает она это регуляркой.
Весь ваш код расчитывает на то, что если передать в эту функцию валидный имейл — она вернёт true. Массив валидных имейлов — тоже true. Массив хотя бы с одним невалидным имейлом — false. Ну и так далее, по коду суть понятна. Но настал день, и вы решили заменить монструозную регулярку внешним API. Но как гарантировать, что переписанная функция не поменяла принцип работы? Вдруг она плохо обработает массив? Или вернёт не boolean? А тесты смогут это всё держать под контролем. Хорошо написанный тест сразу укажет на поведение функции отличное от ожидаемого.
Q: Когда я начну видеть толк от тестов?
А: Во-первых, как только покроете значительную часть кода. Чем ближе покрытие к 100% — тем надёжнее тестирование. Во-вторых, как только придётся делать глобальные изменения, либо же изменения в сложной части кода. Тесты могут отловить такие проблемы, которые вручную могут быть легко упущены (пограничные случаи). Во-третьих, при написании самих тестов! Часто возникает ситуация, когда при написании теста выявляются недостатки кода, которые на первый взгляд незаметны.
Q: Ну вот, у меня сайт на laravel. Сайт это не функция, сайт это хренова гора кода. Как тут тестировать?
А: Именно об этом пойдёт речь дальше. Вкратце: отдельно тестируем методы контроллеров, отдельно middleware, отдельно сервисы, и т. д.
Одна из идей Unit-тестирования заключается в изоляции тестируемого участка кода. Чем меньше кода проверяется одним тестом — тем лучше. Посмотрим пример максимально приближённый к реальной жизни:
Эмуляция, подмена объектов называется моканьем (от англ. mock object, буквально: «объект-пародия»). Никто не мешает писать такие объекты вручную, но всё уже придумано до нас, поэтому на помощь приходит такая чудесная библиотека как Mockery. Давайте создадим моки для сервисов.
Ничего сложного, не так ли? Мы создали заглушки для необходимых параметров класса, создали экземпляр нужного класса, и «дёрнули» нужный метод, передавая заведомо неправильный запрос. Получили ответ. Но как теперь его проверить? Это и есть самая важная часть теста — так называемое утверждение, assertion. PHPUnit имеет десятки готовых assertions. Просто используем одну из них
Данный тест гарантирует следующее — если в метод логин прилетит аргумент-объект у которого не найдётся поля login или password — то метод вернёт строку «Auth error». Вот, в общем-то, и всё. Так просто — но так полезно, ведь теперь мы можем редактировать метод login без страха сломать что-то. Наш frontend может быть уверенным, что в случае чего — он получит именно такую ошибку. И если кто-то сломает это поведение (например, решит изменить текст ошибки) — то тест сразу же об этом просигнализирует! Допишем остальные проверки, чтобы покрыть как можно больше возможных сценариев.
А что же по-поводу зависимостей, спросите вы. Их то мы «заглушили», а вдруг они сломаются? А вот именно для этого и надо максимальное покрытие кода тестами. Мы не будем проверять работу этих сервисов в контексте логина — мы будем тестировать логин рассчитывая на правильную работу сервисов. А потом напишем такие же, изолированные тесты для этих сервисов. А потом тесты для их зависимостей. И так далее. В итоге каждый отдельный тест гарантирует только правильную работу маленького куска кода, при условии что все его зависимости работают правильно. А так как все зависимости тоже покрыты тестами — то их правильная работа тоже гарантируется. В итоге, любое изменение в систему ломающее логику работы даже малейшего участка кода — сразу же отобразится в том или ином тесте. Как конкретно запустить прогон тестов — рассказывать не буду, документация у PHPUnit вполне хорошая. А в Laravel, например, достаточно выполнить vendor/bin/phpunit с корня проекта, чтобы увидеть сообщение вроде этого
— все тесты прошли успешно. Или вроде этого
Один из семи assert-ов провалился.
«Это, конечно, классно, но что из этого я не поймаю руками?» — спросите вы. А давайте для этого представим следующий код
Мы видим упрощённую модель работы с внешним API. Функция использует какой-то класс для работы c API, и в случае ошибки — возвращает null. Если же при использовании этой функции мы получаем null — следует «поднять панику» (отправить сообщение в слак, или имейл разработчику, или кинуть ошибку в кибану. Да куча вариантов). Вроде всё просто, не так ли? Но представим что через некоторое время другой разработчик решил «поправить» эту функцию. Он решил что возвращать null — это прошлый век, и следует кидать исключение.
И он даже переписал все участки кода, где вызывалась эта функция! Все, кроме одного. Его он упустил. Отвлёкся, устал, просто ошибся — да мало ли. Факт лишь в том, что один участок кода всё ещё ожидает старого поведения функции. А PHP это у нас не Java — мы не получим ошибку компиляции на основании того, что throwable функция не завёрнута в try-catch. В итоге в одном из 100 сценариев использования сайта, в случае падения API — мы не получим сообщение от системы. Более того, при ручном тестировании мы скорее всего не отловим этот вариант события. API у нас внешнее, от нас не зависит, работает хорошо — и скорее всего мы не попадём «руками» на случай отказа API, и неверной обработки исключения. Зато будь у нас тесты — они отлично отловят данный кейс, потому что класс ExternalApi в ряде тестов у нас «заглушен», и эмулирует как нормальное поведение, так и падение. И следующий тест у нас упадёт
Этой информации, на самом деле, достаточно. Если у вас не легаси лапша, уже спустя минут 20-30 вы сможете написать свой первый тест. А спустя несколько недель — узнать что-то новое, крутое, вернуться в комментарии под этот пост, и написать какой автор говнокодер, и не знает о %framework_name%, и тесты хреновые пишет, а надо делать %this_way%. И я буду очень рад в таком случае. Это будет значит что моя цель достигнута: кто-то ещё открыл для себя тестирование, и немножечко повысил общий уровень профессионализма в нашей сфере!
Как сделать тестирование на сайте
В сегодняшней статье собираюсь поведать, как сделать тестирование на сайте. Данное тестирование будет аналогично тому, которое имеется на данном сайте, правда, в упрощённом виде. Сразу говорю, если Ваши знания по PHP и MySQL стремятся к нулю, то можете не читать, а лучше поищите в Интернете готовые скрипты тестов. Для тех же, кто обладает необходимым минимумом, а также хочет узнать, как реализуется тестирование на сайте, я и написал данную статью.
Привожу алгоритм, который Вам потребуется уже преобразовать в PHP+MySQL:
Давайте разберём 3-й пункт с кодом:
Теперь давайте разберём 5-й пункт, так как он тоже является, возможно, не совсем понятным:
Самую суть я разобрал, а уже дальше постарайтесь этот алгоритм применить на практике самостоятельно. Ведь не секрет, что придумать алгоритм гораздо тяжелее, чем его реализовать, и Вам нужно лишь его реализовать, а это не так сложно. Не спорю, алгоритм весьма сложный, но я предупредил вначале статьи, что она не для новичков. И несмотря на то, что алгоритм сложный, в реальности он ещё сложнее может быть, если начать добавлять различные «навороты«, например, разбор вопросов в конце, а также каждый раз перемешивать варианты ответов при выводе вопроса.
Копирование материалов разрешается только с указанием автора (Михаил Русаков) и индексируемой прямой ссылкой на сайт (http://myrusakov.ru)!
Добавляйтесь ко мне в друзья ВКонтакте: http://vk.com/myrusakov.
Если Вы хотите дать оценку мне и моей работе, то напишите её в моей группе: http://vk.com/rusakovmy.
Если Вы не хотите пропустить новые материалы на сайте,
то Вы можете подписаться на обновления: Подписаться на обновления
Если у Вас остались какие-либо вопросы, либо у Вас есть желание высказаться по поводу этой статьи, то Вы можете оставить свой комментарий внизу страницы.
Порекомендуйте эту статью друзьям:
Если Вам понравился сайт, то разместите ссылку на него (у себя на сайте, на форуме, в контакте):
Комментарии ( 25 ):
Добавьте результат этого скрипка с рисунком??
Результат здесь: http://myrusakov.ru/tests.html В любой тест заходите вот и будет результат, за вычетом того, что в конце данного скрипта нет разбора вопросов.
Да. Было бы не плохо, если бы появились пункты со скринами, или допустим со ссылками для переходу, где можно было бы просмотреть итог.
Здесь люди учатся, а не занимаются копипастом. Если Вам нужен готовый скрипт, то я, помнится, написал в статье, что нужно делать в этом случае. А если Вы пришли сюда учиться, то, будьте любезны, додумайте задачу сами.
Михаил скажите пожалуйста как мне вытащить все вопросы по определенной теме допустим где test_id=3
Уважаемый Андрей,id каждого вопроса теста не должны повторяться. Можно сделать категорию,занести в неё нужные вам тесты,задать ей id,например,3 и при помощи запроса вытащить все данные из неё.
Уважаемый Александр Альт если Вам не сложно помогите мне пожалуйста я php знаю на среднем уровне до темы регулярные выражения (учусь по курсу Михаила)но мне срочно нужно сделать тестирование поможете сопровождая меня советами?
на данный момент я вывел из базы тему теста вопрос теста и варианты ответа вот файл testing.php а вот файл select_testing.php
Здравствуйте Андрей. Пустое поле в таблице не как не повлияет на работу в целом. Чтобы выводился следующий вопрос из таблицы читайте внимательно пункты 2-7 и делайте по аналогии.
Здравствуйте а можно как то обойтись без сессий? я их еще не изучал а тупо копировать я не хочу так как потом сам же не разберусь в коде в случае чего
Андрей, в сессиях нет ничего страшного, изучайте их так как они очень важные. Сделать это без сессий, Вам будет не возможно.
Скажите как сделать так чтобы при нажатии следующий вопрос выводился следуший вопрос? если можно пример пожалуйста
Лучше реализовать одной кнопкой «Ответ» и после ее нажатия, пользователю автоматически подается следующий вопрос. Реализовать можно множеством способов, зависит от того, как у Вас работает система, можно AJAX’ом допустим.
пример из двух файлов, форма отправки находится в файле form.php, а обработчик в файле add.php. Файлы Вы можете конечно называть как вам угодно, лишь придерживаясь правильности именования файлов и правильно указывайте путь к обработчику. Создайте form.php и добавьте следующий код: Затем, создайте add.php и в него добавьте следующее: Затем, запустите form.php и увидите результат работы передачи данных методом GET.
у меня все получилось но все вопросы выводятся на одной странице как это исправить?
Легкий способ начать тестировать
Если вы PHP-разработчик, и по разным обстоятельствам тесты для своих приложений не пишете, то эта статья для вас. В ней я постараюсь вкратце показать с чего начать и что делать, чтобы написание тестов приносило вам радость, а вашему приложению стабильность.
Итак, первый совет. Забудьте всё что вы знаете о юнит-тестах. Швырните табуреткой в человека, который сказал вам, что без них не обойтись. Попробуем разобраться, в каких случаях нужно их использовать, а в каких — нецелесообразно.
Я абсолютно уверен, что PHP-программисты редко пишут тесты, потому что начинают не с того конца. Все знают, что тесты это хорошо и клево. Но открыв сайт того же PHPUnit, и прочитав красочный пример о тестировании калькулятора умеющего выполнять операцию a + b, они спрашивают себя: какое отношение этот калькулятор имеет к моему приложению? Ответ: никакого. Ровно как все похожие примеры, на сайтах других фреймворков тестирования. Будто бы все забыли, что PHP прежде всего для веба. Будто бы все пишут калькуляторы, а не сайты на основе MVC-парадигмы.
Положим, вы создаете сайт или разрабатываете веб-приложение. На нем уже есть некоторые страницы, формы, возможно даже интерактивные элементы. Как вы (или, допустим, ваш заказчик) проверяете что сайт работает? Наверняка вы заходите на сайт, кликаете по ссылкам, заполняете формы, смотрите на результат. И по-хорошему, все эти рутинные процессы кликанья и заполнения форм, стоит автоматизировать в первую очередь.
И потому мы поговорим о функциональных тестах (или приемочных).
Функциональное тестирование — это тестирование ПО в целях проверки реализуемости функциональных требований, то есть способности ПО в определённых условиях решать задачи, нужные пользователям. Функциональные требования определяют, что именно делает ПО, какие задачи оно решает.
Почему написание тестов стоит начать именно с них? Да просто, чтобы быть уверенным, что ваш сайт функционирует, и всё там работает. Приемочные тесты одинаково хорошо подойдут как для солидного веб-приложения, так и простенького сайта, склепанного за ночь на коленке. А потому начать стоит с них.
Что у нас есть для функционального тестирования? Из всего известного мне, это Codeception и, например, PHPUnit + Mink или прямое использование Selenium. Я хотел включить в этот печерень и Behat, но его автор попросил не использовать Behat для функционального тестирования.
Если бы тестировать с Selenium или PHPUnit + Mink было просто, вы бы уже наверняка их использовали. Потому остановимся на Codeception.
Тест в нем описывается так:
Всего в несколько строчек вы проверяете, что как минимум, главная страница вашего сайта открывается. За длительной работой, сломать её, не так и сложно.
Точно так же, вы можете описывать дальнейшие действия:
Вот тут мы уже проверяем, что форма отзывов на вашем сайте работает. По крайней мере, пользователю, показывается, что его мнение было учтено.
А теперь попробуем определиться, с unit-тестами.
Модульное тестирование, или юнит-тестирование (англ. unit testing) — процесс в программировании, позволяющий проверить на корректность отдельные модули исходного кода программы.
Идея состоит в том, чтобы писать тесты для каждой нетривиальной функции или метода. Это позволяет достаточно быстро проверить, не привело ли очередное изменение кода к регрессии, то есть к появлению ошибок в уже оттестированных местах программы, а также облегчает обнаружение и устранение таких ошибок.
Беда их использования в том, что обычно веб-приложения основываются на CMS или фреймворках. И порой не всегда получается выделить конкретные модули для тестирования. Особенно неудобно получается, когда логика приложения раскидана по различным классам, а каждый конкретный юнит по сути не делает ничего. Процесс тестирования ещё будет усложнен тем, что все модули как-то взаимосвязаны, имеют много унаследованых методов, конфигураций, и выделить где код ваш, а где код библиотеки порой очень трудно.
Но если в рамках функциональных тестов вы проверили всё, что пользователь может сделать, то в юнит-тестах постарайтесь учесть, что он не должен сделать.
Например, проверьте, не позволяет ли ваш код создавать двух пользователей с одинаковыми именами. Проверьте, что при попытке создать дубликат приложение не упадет, и не покажет белый экран смерти, а перехватит ошибку и покажет её текст пользователю. Согласитесь, пользователь, может натворить, гораздо больше, чем вы того хотите. А потому предусмотреть все возможные сценарии и покрыти их функциональными тестами порой невозможно.
Или ещё один пример: у вас на сайте акция — каждый 100ый зарегистрированый пользователь получает подарок. Как бы так проверить, что подарки выдаются, и не создавать при этом 100 лишних пользователей? Вот тут уже пишите юнит-тесты. Без них, скорее всего, никак.
Если в вашем приложении четко выражена бизнес-логика, например: «этот метод создает пользователя, а этот метод позволяет менять статус группы», то вполне резонно покрыть и такие методы юнит-тестами.
И ещё: если вы создаете сайт или приложение на основе своего фреймворка, CMS, или каких-то своих модулей к этим фреймворкам и CMS — обязательно пишите к ним модульные тесты. Тут без вариантов. Если же вы используете сторонние популярные решения, а не изобретаете велосипеды, то скорее всего их код уже протестирован автором и зацикливаться на их тестировании не стоит.
Резюмируя, я бы сказал так: тесты действительно нужны и они не так страшны, как вам могут представляться. Начните написание тестов с приемочных, продолжте модульными. Тестируйте то, что важно и тестируйте то, в чем не уверены.
Disclaimer: прошу прощения за ряд намеренных упрощений и неточностей в статье. С моей точки зрения, они необходимы, чтобы объяснить базовые принципы автоматического тестирования PHP-приложений. Чем больше людей будут тестировать свои приложения, тем лучше станет мир. Ведь главное — начать.
Редакторский дайджест
Присылаем лучшие статьи раз в месяц
Скоро на этот адрес придет письмо. Подтвердите подписку, если всё в силе.
Похожие публикации
Архитектура чистого кода и разработка через тестирование в PHP
Автоматическое тестирование в PHP
Юнит-тестирование в PHP
Вакансии
AdBlock похитил этот баннер, но баннеры не зубы — отрастут
Минуточку внимания
Комментарии 54
Название статьи вам о чем-нибудь говорит?
Я так и не понял: статья о нужности тестирования или о том, все-таки, как же легко начать тестировать?
Ну в нужности тестирования, я полагаю, никто не сомневается. Статья о том, что начинать нужно с функциональных тестов. И то какие лучше элементы тестировать юнит-тестами.
При этом, да, я забыл обозначить, что если вы пишите фреймворк сами, или пишщите к нему отдельныме модули, то конечно, их стоит тестировать изначально.
Я это и без поста знаю.
Я junior, но в следствие проблем с предыдущим проектом, я решил покрыть следующий проект максимально тестами, насколько мне это позволят сроки и другие факторы. Заголовок поста меня заинтересовал, а войдя я даже ссылок на литературу не увидел.
Впринципе, если вы уже начали писать тесты, то стятья уже не для вас.
Вот только, чтобы избежать лишних таубреток уточню: сначала протестируйте вывод в браузер, а потом, тестируйте отдельные методы.
Так-с, уже начинаю понимать. Теперь просто представим, что я внутренний заказчик от которого зависит принятие решений по поводу будет ли использоваться какое-либо тестирование и какое будет.
Она пересыпана терминалогией, которая начинающему незнакома, местами есть отсылки к тому, что перед этим предлагалось забыть. Мне было не трудно забыть, ибо я ничего и так не знаю об юнит-тестах, кроме пары общих фраз. Но оказывается я должен что-то знать все равно 🙂
Часто разделяют автоматизированные тесты веб-приложений на 4 вида (это не касаясь нагрузочных, юзабилити и т. п.):
— приёмочные — проверяют конечный результат, как правило в браузере, то есть что непосредственно знает браузер (и как следствие показывает пользователю), получая html/js/css с сервера со всеми заголовками и т. п., проверяется не только приложение (php-код), но и сервер, и браузер (например JS-код) и прочая среда. Выполняются долго. Запускаются редко.
— функциональные — проверяют почти то же самое, но на более низком уровне, сервер и браузер уже не используются обычно, а проверяется вывод скрипта, то есть что html код соответствует ожидаемому, что в базу внесены нужные изменения и т. п. Зачастую используют эмуляторы браузеров. Выполняются быстрее. Запускаются чаще.
— интеграционные — опускаются ещё ниже, проверяется взаимодействие отдельных слоев приложения, например, что роутер, получив URL (или URI? вечно их путаю), вызовет контроллер с нужными параметрами и что контроллер, получив параметры передаст в шаблон нужные переменные (тесты роутера и тесты контроллера — обычно два разных теста). Выполняются относительно быстро, запускаются часто.
— модульные (юнит) — самый низкий уровень, тестирование отдельных методов, тупо что метод с параметрами возвращает нужное значение. Выполняются очень быстро, запускаются также часто, как нажимается кнопка save или run. В идеале автоматически при её нажатии 🙂
На самом деле разделение довольно условно и зачастую сложно однозначно отнести конкретный тест к одному из слоев (из-за лени разработчиков 🙂 ) — он может быть, например, как и модульный с одной стороны (проверяем вывод в ответ на ввод), так и интеграционный с другой (вывод заключается в вызове другого метода с зависящими от входных параметров). На PHPunit в принципе их писать можно, но ни разу не видел такого.
По хорошему надо тестировать всё, но, скажем, приёмочные тесты отнимают довольно много времени и если нет отдельных тестировщиков, то ими часто пренебрегают (особенно если сложного JS на клиенте нет). Функциональные дают чуть меньшую уверенность в том, что приложение работает как ожидалось, но отнимают относительно мало времени, по сути один тест является спецификацией одной ветки выполнения, то есть переписыванием ТЗ с человеческого языка на алгоритмический в терминах приложения и ЯП. Интеграционные при желании оттестировать всё что можно занимают много времени и часто являются детализацией функциональных, разбивая их на несколько частей, что несколько снижает энтузиазм их написания («это же уже работает!»). Модульные пишутся просто (если архитектура нормальная) и быстро. Если считать функциональные спецификацией приложения, то модульные это спецификация методов, с хорошей архитектурой метод многого делать не должен и спецификации примитивны.
Внутреннему заказчику я бы посоветовал (особенно при работе с существующим приложением без тестов) для начала заказать, чтобы исполнители начинали с функциональных тестов (на новую функциональность или на ту, которую нужно изменить), как минимум для основной ветки выполнения (обычный сценарии работы) и использовали модульные в нетривиальных случаях, когда функциональными добраться до неосновной ветки выполнения сложно и/или долго (например для ситуаций типа «нет места на диске» или «сервер БД недоступен»). При обнаружении бага прежде чем искать его (особенно если сходу не понятно где он конкретно), сначала написать тест, который с этим багом заваливается, а без него должен пройти. При небольшом рефакторинге (типа выделения метода-объекта) писать модульные и интеграционные (если не сложно, а сложно быть не должно) тесты.