Страницы

Поиск по вопросам

вторник, 2 октября 2018 г.

Как запустить тест на Yii2?

Разбираюсь с новым Yii2, подтянул вот этот репозиторий: https://github.com/yiisoft/yii2
Далее подтянул файлы с помощью composer в приложении advanced
Начал смотреть в сторону тестов, ранее никогда с ними не работал, вот и возникли трудности с пониманием этого дела.
Так у нас есть папки с тестами в следующих директориях: backend, common, console, frontend
Я новичок, поэтому сразу хочу начать с самого простого, поэтому будем пока работать с папкой \frontend\tests
Я уже установил у себя phpunit и хочу запустить первый тест для теста =).
Содержимое данной папки такое: https://github.com/yiisoft/yii2/tree/master/apps/advanced/frontend/tests
Честно я почти ничего не понял, что у нас тут и зачем, скорее всего может разные фраэмворки тестов используются, но увидел знакомое название unit и полез туда.
НУ и дальше мои полномочия все. Тоесть подскажите пожалуйста как написать свой первый тест, что там как вообще происходит ?


Ответ

Пришло время обновить ответ. Оригинальную версию можно будет увидеть внизу. Codeception PHPUnit сам по себе никуда не делся, однако ни одно приложение не в состоянии выжить только за счет unit-тестов. Со временем появился Codeception, который представляет из себя большую надстройку над PHPUnit, Selenium и еще кучи пакетов, в которые я сам не заглядывал. Codeception предоставляет три вида тестирования: Acceptance - "приемочное" тестирование, проверка работы пользователя с приложением на основе сценариев (BDD). Functional - функциональное тестирование, функциональная проверка работы приложения. Unit - модульное тестирование, низкоуровневое тестирование конкретных функций. Unit testing С модульным тестированием проще всего - это проверка конкретных функций: создаем массив данных из того, что должно поступить на вход и что должно получиться на выходе, потом прогоняем по этим данным функцию и смотрим, все ли получилось как хотели. Модульное тестирование не ограничивается только этим, но оно рассчитано именно на проверку отдельных функций, методов и модулей, точную сверку выходных данных с требуемыми, проверку состояний тех же модулей. Functional testing Функциональное тестирование появилось тогда, когда стало ясно, что кроме проверки функций необходимо проверять именно работу приложения - что оно не выдает 404 для существующих данных, выдает 403 для закрытых секций, выдает 400 на неправильно введенных данных. Функциональное тестирование постепенно развивалось - коды ответа кодами ответа, а разработчиков интересует именно получение пользователем той или иной информации на странице. Здесь и появилась такая штука, как selenium - сервер, который позволяет запускать браузер и взаимодействовать с ним, и webspider - эмуляция браузера, которая позволяет так же "ходить по страницам". Acceptance testing Codeception же несколько переформатировал понятие функционального тестирования и ввел acceptance testing. В codeception функциональное тестирование - это тестирование страниц через веб-спайдера, acceptance testing - тестирование страниц через браузер. Формально эти тесты могут совпадать с точностью до названия класса, но acceptance testing способен проверять реальную видимость html-элементов на странице и отслеживать работу javascript. Yii первой версии существовал в отрыве от общих стандартов в пользу удобства использования (хотя, честно говоря, не знаю, были ли тогда стандарты). Yii 2 пришел и к неймспейсам, и к обильному использованию чужих пакетов, в том числе codeception. Codeception ставится так же, как и все остальные зависимости Yii - через composer Как использовать codeception? Codeception, как и большинство современных пакетов, предлагает работать с ним через командную строку. Основной исполняемый файл - app_dir/vendor/codeception/codeception/codecept, для удобства я буду писать просто codecept. Проще всего установить codeception глобально и настроить команду-алиас на соответсвующий файл. Сначала необходимо проинциализировать приложение: codecept bootstrap Это создаст папку tests и создаст внутри всю необходимую инфраструктуру. В примерах Yii это уже будет сделано. После этого необходимо настроить codeception с помощью YAML-файлов в tests, но это лучше смотреть сразу в документации Codeception предоставляет возможность писать тесты как на основе PHPUnit_Framework_TestCase (CTestCase из Yii 1.х был оберткой вокруг него), так и на основе своей обертки \Codeception\TestCase\Test. Создать тест проще всего опять же из консоли (предположим, что тест создается для модуля HttpRequest) codecept generate:test unit HttpRequest // Test was created in %app.root%/tests/unit/HttpRequestTest.php Codeception сам добавляет суффикс Test (который позволяет отделять классы-тесты) и расширение .php. Так как скорее всего тестов будет много, можно сразу указать папку, где должен валяться тест. Предположим, полное название HttpRequest на самом деле \Core\Http\HttpRequest и валяется он в папке %app.root%/Core/Http, тогда будет разумно поместить тест в папку %app.root%/tests/Core/Http codecept generate:test unit Core/Http/HttpRequest // Test was created in %app.root%/tests/unit/Core/Http/HttpRequestTest.php Прекрасно, а что мне теперь писать в этом файле? Внутри файл находится класс теста. Этот класс представляет из себя набор методов-тестов, которые проверяют поведение кода, и дополнительных методов инфраструктуры. Каждый метод-тест начинается с префикса test (наприме, testValidate; хорошим тоном будет подставлять название тестируемого метода после префикса, если в тесте проверяется только один метод). PHPUnit посканирует класс и обнаружит все методы, начинающиеся с этого префикса, а затем будет запускать один за другим. Каждый метод теста проверяет поведение кода, используя assert-методы PHPUnit, каждый такой метод проверяет полученные данные. Например, $this->assertTrue($httpRequest->isPostRequest); проверит, соответствует ли true значение $httpRequest->isPostRequest, и в случае, если проверка провалится, оборвет выполнение теста (т.е. только одного метода, если не используется @depends). По поводу "инфраструктурных" методов: любое тестирование сталкивается с тем, что для тестирования требуется настроить окружение, загрузить какие-то данные, создать фальшивые объекты, создать массивы однотипных данных для проверки. Самыми главными здесь будут _before() и _after() (setUp() / tearDown() в PHPUnit) - они будут выполняться до и после выполнения каждого теста в классе, в них обычно выполняет подготовку фальшивого окружения/объектов. Пример класса-теста: class HttpRequestTest extends \Codeception\TestCase\Test { protected $codeGuy; public static function setUpBeforeClass() { $_SERVER['REQUEST_METHOD'] = 'POST'; // в консоли, вероятнее всего, этого ключа изначально вообще не будет } public static function tearDownAfterClass() { unlink('dummy.html'); // стираемый созданный тестом файл } public function testIsPostRequest() { $request = new HttpRequest; // создаем тестируемый объект. В зависимости от характера теста, создание, возможно, будет разумнее вынести в _before() $this->assertTrue($request->isPostRequest); // выполняем непосредственно проверку поведения, сравнивая isPostRequest с true } } А как запустить написанное? Как всегда - из командной строки. Следующая команда запустит все тесты: codecept run Т.к. часто придется обращаться к отдельному виду тестирования или вообще тесту (если отвалился единственный модуль, то толку-то все гонять?), то лучше запускать тесты по этому виду или вообще конкретный тест: codecept run unit // все юнит-тесты codecept run tests/unit/Core/Http/HttpRequestTest.php // конкретный тест, требуется относительный путь с суффиксом и расширением. После этого codeception выведет количество тестов, проверок (один тест может включать в себя несколько проверок) и ошибок. Понятное дело, что любое количество ошибок, отличное от нуля, должно восприниматься как build: failed, и соответствующий код должен немедленно исправляться. Эй, ты ничего не рассказал про остальные два вида тестирования! Потому что сам в них толком пока не поварился (а еще мне лень). В принципе, базовый getting started и любая IDE с подсветкой подскажут что к чему - они ОЧЕНЬ интуитивны. (предыдущая версия текста про PHPUnit) Модульные тесты (unit tests) в PHP в любом фреймворке всегда упираются в один и тот же пакет: phpunit. С чем бы вы не столкнулись, дело придется иметь именно с ним, возможно, в небольшой обертке. Сама суть модульного тестирования заключается примерно в следующем: при разработке какого-то приложения после появления (или изменения) запланированного функционала этого приложения параллельно с самим приложением пишется тестовое сопровождение. Тестовое сопровождение - это, как правило, набор классов, которые по наименованию и расположению повторяют тестируемое приложение, например: Приложение: models/ProductModel.php components/CrmService.php Тесты: tests/models/ProductModelTest.php tests/components/CrmServiceTest.php (контроллеры тут пока специально не упомянуты) Каждый класс - это набор тестов для соответствующего компонента, реально этот набор представлен методами внутри класса теста для этого компонента. PHPUnit автоматом запускает все методы класса, которые начинаются с test (и некоторые другие, но об этом в документации), поэтому типичный класс теста будет представлять собой примерно такую картину: class ProductModelTest extends TestCase { // в данном случае TestCase - та самая обертка, которая будет наследоваться от PHPUnit_Framework_TestCase public function testGet() // негласная конвенция - называть метод по имени тестируемого метода {...} // проверка всевозможных комбинаций входных и выходных значений для метода ProductModel::get() public function testGetAll() {...} public function testValidation() {...} } Теперь непосредственно к yii2. Само приложение advanced представляет из себя просто скелет (точнее, я нашел в common один тест, но он не смог найти codeception), поэтому нам сначала надо будет написать какое-нибудь подобие модели, например, такое. В этой псевдомодели нужно оттестировать все методы, чтобы а) не забыть о недописанных в будущем б) быть уверенным, что в любых стрессовых ситуациях система поведет себя именно так, как надо и в) быть оповещенным ровно в тот момент, как что-то отвалится из-за переписывания низкоуровневых компонент. Соответственно, каждый метод (благо их здесь всего ничего) нужно нашпиговать всеми возможными приходящими значениями и убедиться в корректности отработки (точнее, шпиговать его каждый раз, как что-то поменялось). Я написал для этой модели небольшой и дурацкий тест (ссылка), который занимается ровно этим. Теперь можно проверить работоспособность всей этой конструкции, если модель закинуть в common/models/ProductModel.php, а тест в common/tests/unit/models/ProductModelTest.php. После этого в директории common/tests надо будет выполнить следующую комманду: phpunit --bootstrap _bootstrap.php unit/models/ProductModelTest.php Это запустит соответствующий тест (по умолчанию phpunit будет пытаться загрузить все файлы с названием *Test.php из текущей папки и подпапок; подробнее, как всегда, в доках) и даст примерно следующий вывод: PHPUnit 3.6.10 by Sebastian Bergmann. ....... Time: 0 seconds, Memory: 3.00Mb OK (7 tests, 18 assertions) Который говорит о том, что 7 тестов прошли успешно. Когда я писал модель, я в проверке на id вместо < 1 указал < 0, и в результате все невалидные айдишники прошли, о чем меня и уведомила тестовая проверка: PHPUnit 3.6.10 by Sebastian Bergmann. F...... Time: 0 seconds, Memory: 3.00Mb There was 1 failure: 1) common\tests\unit\models\ProductModelTest::testGet Exception was expected for string input /srv/sandbox/yii2/apps/advanced/common/tests/unit/models/ProductModelTest.php:14 FAILURES! Tests: 7, Assertions: 6, Failures: 1. Такой вот сумбурный ответ. Что касается остальных папок - это файлы для поддержки codeception (в папках с подчерком в начале названия), с которым я сам пока не разобрался (это тестирование более высокого уровня, включающее в себя phpunit), и файлы для различных видов тестирования. На самом деле PHPUnit годится только для библиотек, а для приложений является полумерой, пусть и довольно хорошо защищающей - в приложении должны работать не только модели, но и контроллеры, а для этого недостаточно сымитировать ситуацию - нужно поднять nginx/apache (а лучше оба) и убедиться, что на конкретные запросы приходят верные ответы. Это называется функциональным тестированием, до чего я сам пока не дошел, и осуществляется с помощью загадочной для меня (пока что) программы selenium. Папка functional, соответственно, отвечает за функциональное тестирование. acceptance, насколько понял - это папка для codeception-тестов, который идет еще дальше, и вместо простой проверки запросов/ответов эмулирует клики и отображение для пользователя. Все вместе это называется Continuous Integration (CI) и обеспечивает невозможность выложить в продакшен с некислой посещаемостью и функционалом какой-нибудь серьезный ляп. Я по выходным все пытаюсь развернуть себе полноценный сервер с поддержкой всего этого веселья, но реально в проектах мне пока хватало PHPUnit - остальное, конечно, полезно, но проекты не того масштаба ) В любом случае для ознакомления с тестированием придется сначала поработать только с PHPUnit, поэтому об остальном можно пока не задумываться.

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

Отправить комментарий