Статьи

Разработка через тестирование в PHP

Разработка через тестирование (TDD) лежит в основе гибкой методологии и экстремального программирования . Эта практика известна уже давно, и о ней написано много. Тем не менее, я все еще встречаюсь с разработчиками, которые не знают, что это такое. Я понимаю, что многие работодатели не разрешают своим сотрудникам писать тесты, но мы должны хотя бы знать о лучших практиках в нашей отрасли.

В этом посте я опишу TDD, как я понимаю. Я также расскажу об инструментах, доступных в PHP.

Что такое TDD

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

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

Как практиковать TDD

Практика TDD может быть возобновлена ​​с помощью следующей мантры: красный / зеленый / рефакторинг. Красный — провальный тест. Вы пишете тест для более простой вещи, которую вы можете достичь. Затем вы пишете код для прохождения этого теста и переходите к зеленому. Вы должны написать как можно меньше кода, чтобы пройти тест. Совершите любое преступление, в котором вы нуждаетесь, единственная важная вещь — вернуться к зеленому. Затем на этапе рефакторинга вы исправляете написанный код. Удалите все дубликаты, убедитесь, что код читабелен, используйте описательные имена … Просто убедитесь, что ваши тесты все еще проходят, пока вы выполняете рефакторинг. А потом вы возвращаетесь и пишете еще один провальный тест.

Роберт К. Мартин (дядя Боб) написал «Три правила TDD» . Это отличное чтение, но вот правила:

1. Вам не разрешается писать какой-либо рабочий код, если только он не прошел неудачный модульный тест.
2. Вам не разрешено писать больше модульных тестов, чем достаточно для провала; и ошибки компиляции — это ошибки.
3. Вам не разрешено писать больше производственного кода, чем достаточно для прохождения одного неудачного модульного теста.

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

TDD в PHP

PHP имеет два основных инструмента для модульного тестирования. Простой тест и PHPUnit . Я всегда использовал PHPUnit для модульного тестирования в PHP. Мне нравится инструмент, он интегрируется с Eclipse и может генерировать отчеты о покрытии кода. Очевидно, что Simple Test тоже неплох, но я никогда не пробовал. Вы можете выбрать любой понравившийся вам модуль модульного тестирования, просто начните писать тест.

Чтобы написать модульные тесты с PHPUnit, вы просто создаете файл с именем, оканчивающимся на «Test.php». Если вы хотите протестировать класс с именем KarateChop , вы создаете файл ‘KarateChopTest.php’. В этом файле вы создаете класс KarateChopTest, который расширяет ‘PHPUnit_Framework_TestCase’.

Затем вы создаете свои методы тестирования внутри этого класса. Методы тестирования должны быть открытыми, а их имена должны начинаться с test. Я только что узнал, что вы можете использовать аннотацию @test в блоке документации вместо префикса имени вашего метода с помощью test. Все ваши тесты будут проходить изолированно. Экземпляр класса теста будет создан для каждого метода теста. Просто будьте осторожны с глобальными данными. Глобальные переменные и статические свойства могут затруднить тестирование кода.

Если вашим методам нужен код для подготовки теста, вы можете создать метод setup (). Это будет звонить перед каждым тестом. Вы также можете добавить метод teardown () для очистки после теста.

Ваши методы испытаний должны быть небольшими. Они должны проверять только одно поведение, и каждый тест должен заканчиваться утверждением, которое подтверждает, что ожидаемая система, которая вела себя, тестирует (SUT). Не забудьте написать тест перед реальным кодом. Таким образом, вы можете сначала увидеть, что тест не пройден, и когда он пройдет, вы будете знать, что система работает так, как задумано.

Чтобы проверить результаты вашего теста, PHPUnit имеет широкий спектр утверждений . Они переходят от простого assertTrue к более сложным, таким как assertEqualXMLStructure и assertGreaterThanOrEqual. Я насчитал 36 типов утверждений в документации. У него даже есть метод assertThat для написания тестов в стиле Behavior Driven Development .

Все ваши тесты могут просто использовать assertTrue для проверки условия, но цель вашего кода более очевидна с подробными утверждениями. Эти 2 строки одинаковы:

$this->assertStringStartsWith($prefix, $string);
$this->assertTrue(0 === strpos($string, $prefix)); 

 Но первый говорит, что я тестирую.

Чтобы запустить ваши тесты, все, что вам нужно сделать, это запустить phpunit, передав ему файл с тестами в качестве параметра. Если вы передадите ему папку, PHPUnit будет запускать тест для всех файлов с именем, оканчивающимся на «Test.php» в этой папке и любых подпапках.

Бутстрапирование

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

phpunit --bootstrap Tests/testBootstrap.php .

Тестирование баз данных

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

Однако мы работаем в реальном мире, и нам иногда приходится тестировать код, который обращается к базе данных. Чтобы сделать это проще, вам не следует создавать соединение, а требовать его в конструкторе объектов или в качестве параметра для метода, который его использует. Если вы не можете сделать это, подумайте о создании сеттера, который позволит вашему тестовому коду вводить другое соединение

Убедитесь, что вы используете соединения PDO и попробуйте придерживаться стандартного SQL. Таким образом, в своих тестах вы можете создать базу данных SQLite и передать ее своим тестам. Убедитесь, что вы создаете базу данных в памяти, а не в файле. Таким образом, у каждого теста будет своя собственная база данных, и они останутся изолированными. Создание такой базы данных может стать очень громоздким, если вы используете много таблиц или вам нужно заполнить их большим количеством поддельных данных.

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

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

PHPsrc

Я уже писал о PHPsrc в предыдущем посте . Этот инструмент позволит вам запускать ваши тесты из Eclipse.

Конфигурация PHPsrc PHPUnit

Конфигурация PHPsrc PHPUnit

Интеграция с PHPUnit позволит вам легко запускать тесты. Он также может прыгать между тестами и тестируемым классом. Вы можете дать ему файл начальной загрузки в конфигурации. Либо в глобальных настройках, либо по проекту. Он будет подчеркивать неудачные тесты как ошибки, а также может показывать код, который не охватывается вашими тестами.

Когда начать

Начало TDD не простая задача. Сначала это замедлит вас. Может показаться, что вы потеряли некоторую производительность, но вам следует наверстать довольно быстро. Особенно, когда вы будете поддерживать свой код. После этого вы сможете вносить изменения, будучи уверены, что ничего не сломали.

Если вы хотите быть хорошим во всем, вам нужно практиковаться. Есть много ресурсов, доступных для практики TDD. Вы можете выполнить код Code Kata , попробовать отступление кода , найти Coding Dojo или попробовать CyberDojo . Все это отлично, просто иди и практикуйся.

Если вам нужна дополнительная информация о TDD, я бы порекомендовал почитать Test Driven Development: By Example by Kent Beck . Он начинается с подробного объяснения TDD и заканчивается реализацией инфраструктуры xUnit в TDD.