Как установить phpunit через composer
Перейти к содержимому

Как установить phpunit через composer

Getting Started with PHPUnit 7

This tutorial assumes that you use PHP 7.1. You will learn how to write simple unit tests as well as how to download and run PHPUnit.

The documentation for PHPUnit 7 can be found here.

Download

PHP Archive (PHAR)

We distribute a PHP Archive (PHAR) that contains everything you need in order to use PHPUnit 7. Simply download it from here and make it executable:

Composer

You can add PHPUnit as a local, per-project, development-time dependency to your project using Composer:

Please refer to the documentation for details on how to verify PHAR releases of PHPUnit.

The example shown above assumes that composer is on your $PATH .

Your composer.json should look similar to this:

Test Code

Test Execution

PHP Archive (PHAR)

The above assumes that you have downloaded phpunit.phar and put it into your $PATH as phpunit and that src/autoload.php is a script that sets up autoloading for the classes that are to be tested. Such a script is commonly generated using a tool such as phpab.

Composer

The above assumes that vendor/autoload.php , the autoloader script managed by Composer, exists and is able to load the code for the Email class. Depending on how you set up autoloading, you may need to run composer dump-autoload now.

—bootstrap src/autoload.php instructs the PHPUnit command-line test runner to include src/autoload.php before the tests are run.

tests instructs the PHPUnit command-line test runner to execute all tests found declared in *Test.php sourcecode files in the tests directory.

tests instructs the PHPUnit command-line test runner to execute all tests found declared in *Test.php sourcecode files in the tests directory.

TestDox

Below you see an alternative output which is based on the idea that the name of a test can be used to document the behavior that is verified by the test:

Модульное тестирование (Unit tests) с помощью PHPUnit

Зачем нужны тесты и какие виды тестов должен писать разработчик вы можете узнать здесь.

Адриан Кун (Adrian Kuhn) и другие:

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

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

Часто существуют неявные зависимости между тестовыми методами, скрытые в сценарии реализации теста.

Установка PHPUnit и написание первый тест

Для начала нужно установить версию php7.2+ и composer. Затем в проекте устанавливаем phpunit:

Создаем пример для теста Duck.php:

Создаем папку tests и добавляем туда тестируем класс DuckTest.php (по умолчанию PHPUnit смотрит на все файлы в которые заканчиваются на Test.php).

И запускаем тесты:

Если вы увидели такое сообщение, то все сделано верно.

Базовые вещи, которые нужно знать:

Фикстуры (Fixture)

Фиксутра — настройка окружения и возврат его в исходное состояние. Звучит страшно, но на самом деле это просто методы, которые позволяют настроить окружение для теста. В классе \PHPUnit\Framework\TestCase для этого есть методы:

  • setUp выполняются перед каждым тестом тестового класса;
  • tearDown выполняются после каждого теста тестового класса;
  • setUpBeforeClass — выполняется перед первым тестом в тестовом классе;
  • tearDownAfterClass — выполняется после запуска последнего теста тестового класса.

Получается в каждом тестируемом методе свойство counter будет равно 0.

Утверждение (Asserts)

Утверждения — это методы класса TestCase, которые помогают проверить тест. Все эти методы начинаются с assert (assertTrue, assertSame, assertClassHasAttribute и т.д.). После выполнения тестов будет показано кол-во выполненных тестов и кол-во выполненных утверждений. В случае неверного утверждения тест считается проваленным.

Тестовые двойники (Заглушки, Stubs, Mocks)

Stub — объект, который заменяет реальный объект. Например у нас есть класс Duck в конструктор которого должен попасть объект Headdress:

Mock — отличается от стаба тем, что еще описывает какое-то поведение и его изменение влияет на выполнение теста.

При тестировании одного класса в разных его методах один и тот же внешний объект может быть как моком, так и стабом.

В нашем примере мы еще описали, что ожидаем, что Duck при вызове метод run вызовет внутри себя метод back объекта Headdress .

Настройка окружения для всех тестов (Bootstrap)

Для настройки окружения для всех тестов можно создать файл bootstrap.php и объявить там необходимые вещи. Например в этом файле мы можем подключить библиотеки необходимые для тестирования, изменить глобальные и супер-переменные, объявить константы и т.д.

Пример bootstrap.php файла:

Конфигурационный XML-файл

Мы можем настроить выполнение команд с помощью конфигурационного XML-файла, в котором можно изменить стандартные настройки phpunit, указать папку с тестами, путь к бутстап файлу, настроить фильтры и другое.

Атрибутами или вложенными тегами к <phpunit> могут быть любые команды, которые есть в phpunit. В нашем случае

Покрытие тестами (Tests coverage)

С помощью этого инструмента очень легко понять насколько качественно написаны тесты, сколько файлов покрыты тестами и какие строки в них покрыты. Данный инструмент очень сильно помогает отслеживать качество ваших тестов.

Необходимо к вашему php-cli подключить xdebug иначе coverage будет недоступен и вы получите уведомление об отсутствии модуля для тестирования.

Чтобы его использовать достаточно дописать к phpunit —coverage- атрибут. Например очень удобно использовать HTML-формат покрытия:

После этого в проекте создается папка coverage и мы можем открыть файл index.html и просмотреть подробную информацию о каждом файле тестирования.

Суровый русский тимлид. Жил в Магадане, в офисе московских веб студий и в Тульской деревне. Виртуозно знает WordPress, PHP, ООП, Vue.js и вот это вот все.

Делает крутые высоконагруженные сайты, поэтому уже почти захватил весь рынок WordPress разработки в России. Не дает никому делать сайты без спроса.

Разворачиваем автоматизацию за пару часов: PHPUnit, Selenium, Composer

Привет, Хабр! Меня зовут Виталий Котов, я работаю в Badoo, в отделе QA. Большую часть времени занимаюсь автоматизацией тестирования. Недавно я столкнулся с задачей максимально быстро развернуть Selenium-тесты для одного из наших проектов. Условие было простое: код должен лежать в отдельном репозитории и не использовать наработки предыдущих автотестов. Ах, да, и нужно было обойтись без CI. При этом тесты должны были запускаться сразу после изменения кода проекта. Отчёт должен был приходить на почту.

Собственно, опытом такого развёртывания я и решил поделиться. Получился своего рода гайд «Как запустить тесты за пару часов».

Условия задачи

Прежде всего стоит декомпозировать задачу на несколько подзадач. Получается, что наша миссия, если мы возьмемся за её исполнение, заключается в следующем:

  • нужен отдельный репозиторий;
  • в нём должны лежать тесты;
  • в нём должен лежать некий механизм, который будет запускать тесты по изменению кода проекта;
  • отчёт должен быть читаемым, удобным и приходить на почту указанным людям.

В Badoo первые Selenium-тесты были написаны на PHP на основе фреймворка PHPUnit. Сервер Badoo по большей части написан на PHP и к моменту, когда появилась автоматизация, было решено не плодить технологии.

Для работы с Selenium тогда был выбран фреймворк от Facebook, но в какой-то момент мы так увлеклись добавлением туда своего функционала, что наша версия перестала быть совместимой с их.

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

Я скачал composer, с помощью которого собирать такой проект мне показалось удобнее:

Файл composer.json выглядел тогда так:

Класс MyTestCase

Первое, что требовалось сделать, — это написать свой TestCase-класс:

В нём появились функции setUp и tearDown, которые создавали и убивали Selenium-сессию, и функция onNotSuccessfulTest, которая обрабатывала данные упавшего теста:

В setUp всё довольно просто: мы создаём сессию, указав URL Selenium-фермы и желаемые capabilities. На этом этапе меня интересовал только браузер, на котором мы собирались гонять тесты.

C tearDown всё несколько хитрее.

Суть вот в чем. Для упавшего теста tearDown выполняется до того, как выполнится onNotSuccessfulTest. Следовательно, если мы хотим закрывать сессию в tearDown, все необходимые данные из неё стоит получить заблаговременно: текущая локация, скриншот и HTML-слепок, значения cookie и прочее. Все эти данные потребуются нам для формирования красивого и понятного отчёта.

Собирать данные, соответственно, следует только для упавших тестов, помня о том, что tearDown будет вызываться для всех тестов, включая успешно прошедшие, skipped и incomplete.

Сделать это можно как-то так:

Класс ArtifactsHelper, как нетрудно догадаться из названия, помогает собирать артефакты. Но о нём чуть позже. 🙂

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

Далее следует onNotSuccessfulTest, где нам понадобится ReflectionClass. Выглядит он так:

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

Класс ArtifactsHelper

Класс довольно простой, так что расскажу о нём очень коротко. Он создаёт файлы, которые называются как упавший тест плюс таймстемп, и помещает их в соответствующую папочку. После прогона всех тестов файлы добавляются в итоговый email с отчётом и удаляются. Выглядит это дело примерно так:

В конструкторе мы создаём нужную директорию, если её нет, и привязываем driver к локальному полю, чтобы было удобнее им пользоваться.

Методы takeLocalScreenshot и takeLocalSource создают файлы со скриншотом (.png) и HTML-слепком (.html). Они будут называться именем теста, только мы заменим часть символов на другие, чтобы название файла не смущало файловую систему.

Тесты

Тесты у нас будут наследоваться от MyTestCase. Приводить примеры не буду — всё стандартно. Через $this->driver мы работаем с Selenium, а все assert’ы и прочее выполняем через $this.

Стоит сказать несколько слов про передачу параметров для запуска тестов. PHPUnit не даст при запуске теста из консоли добавить какой-то незнакомый ему параметр. А это было бы очень удобно, например, чтобы иметь возможность задавать желаемый браузер для тестов.

Я решил эту проблему следующим образом: создал папочку bin/ в корне проекта, куда положил исполняемый файл с названием phpunit следующего содержания:

А в классе MyCommand, соответственно, прописал желаемые параметры:

Теперь, если запускать тесты от нашего phpunit-файла, можно задавать параметры, которые будут передаваться в тесты в массив $GLOBALS[‘argv’]. Дальше его можно парсить и как-то обрабатывать.

Запуск по изменению кода проекта

Итак, теперь у нас есть всё для того, чтобы начать запускать тесты по триггеру. К сожалению, репозитория с кодом проекта у нас нет, так что узнать, когда были совершены изменения в нём, не представляется возможным. Без помощи разработчиков тут не обойтись.

Мы договорились, что в тестовом окружении у приложения будет специальный адрес, по которому можно будет увидеть хеш последнего коммита (по сути, версия сайта).

Дальше всё просто: по cron запускаем специальный скриптик раз в пару минут. При первом запуске он идёт при помощи Curl по этому адресу и получает текущую версию сайта. Далее он создаёт в специальной директории файлик version.file, куда пишет эту версию. В следующий раз он получает версию и с сайта, и из файлика; если они отличаются, записывает новую версию в файл и запускает тесты, Если нет — не делает ничего.

В итоге всё выглядит примерно так:

Отправка письма с отчётом

К сожалению, в PHPUnit из класса TestCase невозможно определить, последний ли тест прошёл в сьюте или нет. Конечно, там есть метод tearDownAfterClass, но он выполняется после завершения тестов в одном классе. Если в сьюте указаны, например, два класса с тестами, tearDownAfterClass исполнится дважды.

Мне же нужно было где-то прописать логику, которая будет отправлять письмо гарантированно после прохождения всех тестов. И, конечно, делать это только один раз. Как вы уже догадались, я написал очередной хелпер. 🙂

Класс Mailer

Этот класс хранит в себе информацию о прошедших тестах: тексты ошибок, пути до файла со скриншотом и HTML-слепком. Он сделан по принципу Singleton, инстанцируется единожды при первом вызове. И не уничтожается принудительно. Понимаете, к чему я веду? 🙂

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

В зависимости от того, прошли тесты успешно или нет, меняется заголовок письма. Если версия сайта менялась в течение прогона, тесты запускаются повторно.

Автопул тестов

Ну и напоследок немного удобства. Так как вся эта система будет жить где-то на удалённом сервере, было бы удобно, если бы она сама умела делать git pull, чтобы случайно не забыть подмёржить важные изменения в тестах.

Для этого создаём исполняемый файлик следующего содержания:

Скрипт исполнит команду git pull, и, если что-то пойдёт не так и ему это не удастся, напишет письмо ответственному сотруднику.

Дальше добавляем скрипт в cron, запуская раз в пару минут, — и дело в шляпе.

Итоги

Итоги обычно подводят с оглядкой на изначальную задачу. Вот что у нас получается:

  • появился отдельный репозиторий;
  • там при помощи сomposer мы собрали проект: скачали PHPUnit и фреймворк Facebook;
  • написали свой TestCase-класс, который умеет генерить удобные отчёты;
  • написали тесты, которые можно запускать в разных браузерах и с разными параметрами;
  • создали механизм, который будет запускать эти тесты при изменении версии тестируемого проекта;
  • позаботились об отправке письма с отчётом и скриншотами;
  • добавили скрипт, который автоматически всё это дело обновляет до нужной версии.

Такая вот история. Спасибо за внимание! Буду рад услышать ваши истории, пишите в комментариях. 🙂

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

Ваш адрес email не будет опубликован. Обязательные поля помечены *