PHPUnit — введение

К сожалению, т.к. Ivan Verber удалил свой перевод документации PHPUnit с своего сайта, я решил опубликовать переведенный им материал, а в будущем улучшить. А пока, то что есть, как говорится.

Глава 1. Автоматизация Тестирования

Даже хорошие программисты ошибаются. Разница между хорошим и плохим программистом в том, что хороший программист использует тесты, чтобы обнаружить свои ошибки как можно раньше. Чем раньше вы проверите свой код на наличие ошибки тем больше ваши шансы найти её и тем меньше будет стоить её поиск и исправление. Это объясняет почему тестирование становится большой проблемой если его откладывать до релиза. Большинство ошибок не будут найдены совсем, а цена исправления тех, которые были пойманы, будет так высока, что вам придётся отобрать (и исправить) только некоторые из них, потому что вы просто не сможете себе позволить исправить их все.

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

В этой главе мы перейдём от простого тестового кода основанного на print-ах к полностью автоматизированному тесту. Представьте себе что вас попросили протестировать встроенный в PHP array. Одна из частей функциональности, которую нужно протестировать - функция count(). Для только что созданного массива мы ожидаем что функция count() вернёт 0. После добавления одного элемента count() должна вернуть 1Пример 1.1, «Тестирование работы с массивами» демонстрирует то что мы хотим протестировать.

Пример 1.1. Тестирование работы с массивами

<?php
$fixture = array();
// ожидается, что $fixture будет пустой.

$fixture[] = 'element';
// ожидается, что $fixture содержит один элемент
?>

Самый простой способ проверить что мы получаем в результате то что мы ожидали - это распечатать результат count() до и после добавления элемента (см. Пример 1.2, «Используем print для проверки операций с массивами»). Если мы получим 0 а затем 1array иcount() работают так как ожидалось.

Пример 1.2. Используем print для проверки операций с массивами

<?php
$fixture = array();
print count($fixture) . "\n";

$fixture[] = 'element';
print count($fixture) . "\n";
?>
0
1

Теперь, нам бы хотелось перейти от тестов, которые требуют интерпретации в ручном режиме, к тестам, которые мы сможем запускать автоматически. В Пример 1.3, «Сравнение ожидаемого и реального значения для тестирования операций с массивами» мы дописали сравнение ожидаемых и реальных значений в тестовом коде и выводим ok если значения равны. Если мы когда-нибудь увидим сообщение not ok, мы будем знать что что-то пошло не так

Пример 1.3. Сравнение ожидаемого и реального значения для тестирования операций с массивами

<?php
$fixture = array();
print count($fixture) == 0 ? "ok\n" : "not ok\n";

$fixture[] = 'element';
print count($fixture) == 1 ? "ok\n" : "not ok\n";
?>
ok
ok

Теперь мы выделим сравнение ожидаемых и полученных значений в функцию, которая поднимет исключение когда обнаруживает несоответствие (Пример 1.4, «Использование функции-утверждения (assertion function) для тестирования операций с массивами»). Это даёт нам два преимущества: написание тестов упрощается и мы получаем сообщение когда что-то не так.

Пример 1.4. Использование функции-утверждения (assertion function) для тестирования операций с массивами

<?php
$fixture = array();
assertTrue(count($fixture) == 0);

$fixture[] = 'element';
assertTrue(count($fixture) == 1);

function assertTrue($condition)
{
    if (!$condition) {
        throw new Exception('Assertion failed.');
    }
}
?>

Глава 2. Цели 

Тест теперь полностью автоматизирован. Теперь вместо тестирования которое мы выполняли в нашей первой версии, в этой версии мы имеем автоматизированый тест.

Цель использования автоматических тестов в том чтобы делать меньше ошибок. И хотя ваш код всё еще будет несовершенен, даже при отличных тестах, вы скорее всего увидите разительное снижение количества дефектов как только вы начнёте автоматизировать тесты. Автоматизированные тесты дают вам обоснованную уверенность в коде. Вы можете использовать эту уверенность для того, чтобы предпринимать более смелые шаги в дизайне (Рефакторинг), лучше работать с товарищами по команде (Командное Тестирование [Cross-Team Tests]), улучшить отношения с вашими клиентами, и каждый раз вечером уходить домой с уверенностью что система стала лучше чем она была утром благодаря вашим усилиям.

Пока у нас есть только два теста для встроенного типа array и функции count(). Если мы начнём тестирование многочисленных функций array_*() которые предоставляет PHP нам придётся написать тест для каждой из них. Мы могли бы написать инфраструктуру для всех этих тестов с нуля. Однако, гораздо лучше написать один раз тестовую инфраструктуру, а затем писать только уникальные части каждого теста. PHPUnit как раз и является такой инфраструктурой.

Такой фреймворк как PHPUnit должен соответствовать ряду требований, и некоторые из них противоречивы. Итак, тесты должны быть одновременно:

Простыми в изучении.

Если будет сложно научиться писать тесты, разработчики не будут учиться писать тесты.

Простыми в написании.

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

Легко читаемыми.

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

Легко исполняемыми.

Тесты должны запускаться по нажатию одной кнопки и представлять результат в ясном и недвусмысленном формате.

Быстро исполняемыми.

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

Изолированными.

Тесты не должны влиять друг на друга. Если порядок запуска тестов меняется результат тестов должен оставться неизменным.

Комбинируемыми.

Мы должны иметь возможность запускать совместно любое количество тестов в любых комбинациях. Это является естественным следствием изоляции.

Существуют два основных противоречия между этими требованиями:

Простота изучения против простоты написания

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

Изоляция простив скорости исполнения.

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

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

PHPUnit жертвует скоростью выполнения тестов в пользу изоляции. Изолированные тесты важны, потому что они обеспечивают высокое качество обратной связи. Вы не получите отчёт с кучей ошибок, только потому что один тест в начале пакета провалился и оставил окружение поломанным для остальных тестов. Такая ориентация на изоляцию тестов приводит к архитектуре с большим числом простых объектов. Каждый объект может быть протестирован быстро и изолировано. Результат - лучшая архитектура и более быстрые тесты.

PHPUnit предполагает, что большинство тестов успешны и они не стоят подробного отчёта. Однако, если тест провален, то этот факт стоит отметить в отчёте. Большая часть тестов должна быть успешна и она не стоит комментариев, кроме подсчёта количества выполненных тестов. Это предположение по сути встроено в логику классов отчётов, а не в ядро PHPUnit. При отображении результатов запуска тестов вы видите сколько тестов выполнилось, но только для проваленных тестов вы увидите детали.

Ожидается что тесты "мелкозернисты" и каждый будет тестировать отдельный аспект одного объекта. Таким образом, как только тест падает его выполнение прекращается и PHPUnit сообщает о неудаче. Умение протестировать [систему] с помощью множества маленьких тестов - натоящее искусство. "Мелкозернистые" тесты улучшают архитектуру системы.

Когда вы тестируете объект с помощью PHPUnit вы работаете только через публичный интерфейс. Тестирование только публично доступного поведения способствует выявлению и решению сложных архитектурных проблем до того как последствия плохого дизайна заразят большую часть системы.

Оцени публикацию:
  • 0,0
Оценили человек: 0

Похожие статьи:

Справочники и учебники:


Предложения и пожелания:
Ваше имя:
Ваш E-mail:
Сколько будет Οдин + Τри
Главная
X

youtube.com/watch?v=7hFivbgIEqk

При полном или частичном использовании материалов данного сайта, ссылка на сайт "yapro.ru" обязательна как на источник информации.
Автоматический импорт материалов и информации с сайта запрещен.
Copyrights © 2007 - 2017 YaPro.Ru

Главная » Веб-мастеру » PHP »