Тестирование кода с PHPUnit

Тестирование кода с PHPUnit

От автора: при разработке веб-приложений так или иначе будут возникать различные ошибки и неточности в работе некоторых элементов, на поиск и исправление которых можно затратить значительное количество времени. Поэтому в данном уроке мы с Вами познакомимся с очень хорошим инструментом библиотеки PEAR, который позволяет выполнять тестирование отдельных элементов будущего скрипта. Название данного инструмента PHPUnit.

скачать исходникискачать урок

1. Установка PHPUnit

PHPUnit – это специальный фреймворк, предназначенный для модульного тестирования скриптов языка PHP, разработанный Себастьяном Бергманом. Преимущества PHPUnit:

Инструменты для создания модульных тестов и организации их в иерархические наборы.

Интерфейс командной строки для выполнения тестов.

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

Поддержка тестирования кода, работающего с базой данных.

Тестирование исключений.

Поддержка так называемых фиктивных объектов.

Генераторы отчетов.

Работа данного фреймворка не возможна без установленной в Вашем интерпретаторе языка PHP библиотеки PEAR. Конечно, сейчас мы не будем подробно останавливаться на данной библиотеке, потому как это не тема данного урока.

Но кратко скажу, что PEAR — это аббревиатура от «PHP Extension and Application Repository» (Репозиторий приложений и модулей PHP). То есть PEAR – это набор классов и модулей, которые существенно расширяют функционал языка PHP и каждый из них, это законченное веб-приложение, выполняющее свои цели и задачи. Поэтому первым делом необходимо установить библиотеку PEAR. Для этого перейдем на сайт http://pear.php.net/:

Далее кликаем по ссылке: installing PEAR on your system.

Затем переходим оп ссылке Getting and installing the PEAR package manager:

На данной странице нам необходимо скачать установочный файл библиотеки PEAR. Поэтому кликаем по ссылке: http://pear.php.net/go-pear.phar. Скачанный файл необходимо поместить в папку с интерпретатором языка PHP. Если Вы используете Denwer, то данная папка содержится по адресу: usr/local/php5. Теперь открываем командную строку, переходим в папку с интерпретатором языка PHP и набираем команду:

php go-pear.phar

Да, хотел бы сказать, что если у Вас в системной переменной $path (переменные среды) прописан путь к интерпретатору PHP, то предыдущую команду можно выполнять, находясь в любой папке.

Далее, выбираем режим установки local (то есть, набираем команду local) и подтверждаем свой выбор, набором строки “yes”:

Далее необходимо проверить пути установки отдельных компонентов библиотеки (то есть, как Вы видите перед началом установки, показано куда будут установлены элементы библиотеки.). Я Вам рекомендую устанавливать библиотеку PEAR в папку с интерпретатором PHP. Если Вам нужно отредактировать путь установки, наберите в командной строке 1 и выберите папку для установки. Если все верно нажимаем ENTER и начинается установка:

Итак, библиотека PEAR успешно установлена. Теперь необходимо установить PHPUnit. Для этого перейдем на сайт http://pear.phpunit.de/. Здесь, как Вы видите, подробно описан процесс установки инструмента PHPUnit и ниже представлено подробное описание, доступные версии и так называемые зависимости. То есть элементы, которые необходимы для нормальной работы и установки PHPUnit.

Теперь возвращаемся в командную строку и в соответствии с инструкцией добавляем следующую команду, которая зарегистрирует канал установки инструмента PHPUnit:

pear channel-discover pear.phpunit.de

Далее для правильной установки PHPUnit, необходимо зарегистрировать канал компонента pear.symfony (без него PHPUnit работать не будет). Поэтому перейдем на сайт http://pear.symfony.com и в верхней части сайта Вы увидите аналогичную инструкцию по регистрации канала symfony. Поэтому в командной строке выполним следующую команду

pear channel-discover pear.symfony.com

Далее устанавливаем PHPUnit, выполнив в командной строке следующую команду:

pear install phpunit/PHPUnit

Как Вы видите PHPUnit успешно установлен. Для проверки его работоспособности, достаточно выполнить команду phpunit. На экране Вы увидите небольшую справку по данному инструменту.

2. Создаем первый тест

Итак, давайте рассмотрим следующий класс (файл sqrt_class.php):

<?php
	class sqrt_class {
	
		public function sq($x)
		{
			if($x == 5) {
				return TRUE;
			}
			if($x == 100) {
				return FALSE;
			}
			return sqrt($x);
		}
	}
?>

Как Вы видите, это очень простой класс, который содержит всего один метод, возвращающий корень квадратный переданного ему параметра $x. Также данный метод проверяет значение данного параметра и если оно равно 5, значит, возвращаем TRUE. Если же значение параметра $x равно 100, значит, вернем FALSE.

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

require_once 'PHPUnit/Autoload.php';

Затем подключаем класс, который нужно протестировать:

require_once 'sqrt_class.php';

Перед созданием класса для тестирования рассмотрим несколько правил создания таких классов:

Название класса теста складывается из названия тестируемого класса плюс “Test”.

Класс для тестирования практически всегда должен быть наследником класса PHPUnit_Framework_TestCase.

Каждый метод теста является публичным методом, название которого начинается с префикса “test”.

Внутри метода теста мы используются специальные методы тестирования – assert-методы. Которые и задают способ тестирования.

Теперь создадим класс для тестирования (для лучшего понимания приведу полный код файла test.php):

<?php
require_once 'PHPUnit/Autoload.php';
require_once 'sqrt_class.php';

class sqrt_classTest extends PHPUnit_Framework_TestCase {
	public function testSq() {
		$my = new sqrt_class();
		//метод assertEquals(), который первым обязательным параметром принимает ожидаемое значение, вторым актуальное и проверяет их соответствие.
		$this->assertEquals(4, $my->sq(16));
	}
}
?> 

Как Вы видите, класс для тестирования достаточно простой и содержит всего один метод testSq. Имя данного метода выбрано в соответствии с выше изложенными правилами. То есть мы хотим протестировать метод sq(), значит, имя будет таким же, но с добавлением префикса test. В данном методе, мы создаем объект класса sqrt_class() (класс, метод которого мы хотим протестировать), и сохраняем его в переменной $my. Теперь в зависимости от того, какой тест нужно выполнить, необходимо вызвать специальный assert-метод.

Для первого теста, мы применим метод assertEquals(), который первым параметром принимает ожидаемое значение (то есть то верное значение которое должен возвращать метод), вторым — реальное значение (то есть значение которое действительно возвращается методом). И сравнивает эти два значения. Если они равны – тест пройден успешно. Если же нет — то ошибка.

Теперь как Вы видите, при вызове метода assertEquals(), первым параметром мы передаем значение 4, как ожидаемое. И вторым, передаем вызов метода sq() класса sqrt_class – как реально вычисленное значение. Параметром к методу sq(), передадим значение 16. Значит в результате отработки метода мы должны получить число 4, при этом ожидаемое значение, мы так же передали 4. Значит, тест должен завершиться успешно. Поэтому, давайте выполним тест и проверим.
Для запуска теста, необходимо вернуться в командную строку, перейти в папку с интерпретатором языка php и набрать команду:

phpunit path,

где path – это путь к файлу с тестом, в нашем случае это файл test.php. То есть в командной строке выполняем команду:

phpunit z:\home\localhost\www\for_pear\test.php

В результате мы увидим следующее:

Итак, что мы видим. Первое, что бросается в глаза – это приветствие, то есть версия PHPUnit и имя создателя. Далее – точка. Точка – это признак того, что тест выполнен успешно. Затем указана, различная сервисная информация (количество затраченного времени, памяти и т.д). Теперь давайте, изменим ожидаемое значение, с 4 на 2 (то есть первым параметром методу assertEquals() передадим 2) и запустим тест:

Теперь вместо точки мы видим букву F, что означает Fault – ошибка. Ниже можно прочитать в чем именно заключается ошибка теста. То есть тест закончился с ошибкой.

В данном примере, мы рассмотрели передачу двух параметров в метод assertEquals(), но что делать, если нужно протестировать отработку метода, для различных параметров. Не будем же мы для каждого набора параметров, вручную запускать тест? Конечно нет. Для решения данной задачи, необходимо использовать провайдеры данных. Провайдеры данных, содержат в себе массив параметров, которые будут подставлены во время запуска теста. Тем самым, запуская тест мы выполним столько тестов, сколько наборов параметров содержится в провайдере данных.

Провайдер данных это обычный метод, который возвращает массив с набором параметров следующем формате:

public function providerSq ()
	{
		return array (
			array (param1, param2),//параметры для тест 1
			array (param1, param2),// параметры для  тест 2
			array (param1, param2),// параметры для тест 3
			array (param1, param2)// параметры для тест 4
		);
	}

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

Метод являющийся провайдером, должен быть назван, как и тестируемый метод, с добавлением приставки provider.

Перед тестируемым метод, необходимо указать в специальном комментарии название его провайдера. Следующим образом:

/**
	* @dataProvider имя провайдера
	*/

Поэтому давайте изменим код класса sqrt_classTest, для использования провайдеров:

class sqrt_classTest extends PHPUnit_Framework_TestCase {
	/**
	* @dataProvider providerSq
	*/
	public function testSq($a,$b) {
		$my = new sqrt_class();
		$this->assertEquals($a, $my->sq($b));
	}
	
	public function providerSq ()
	{
		return array (
			array (2, 4),
			array (4, 16),
			array (5, 5),
			array (3, 100)
		);
	}
}

Теперь, давайте выполним данный тест:

Как Вы видите, сейчас выполнилось четыре теста – для каждого набора параметров. Четвертый тест выполнился с ошибкой. Так как корень квадратный из 100, ни как не может быть равен 3. Наряду с методом assertEquals, есть еще два полезных метода assertTrue() и assertFalse(), которые проверяют, является переданное выражение истинным или ложным соответственно. То есть, метод для тестирования истинности возвращаемого значения:

/**
	* @dataProvider providerSq
	*/

public function testSq($a,$b) {
		$my = new sqrt_class();
		$this->assertTrue($my->sq($b));
	}

Данный тест успешно выполнится если метод sq(), вернет TRUE. И метод для тестирования того, что тестируемый метод вернет FALSE:

/**
	* @dataProvider providerSq
	*/
	public function testSq($a,$b) {
		$my = new sqrt_class();
		$this->assertFalse($my->sq($b));
		
	}

Данный тест успешно выполнится если метод sq(), вернет FALSE.

3. Тестирование массивов

Теперь давайте рассмотрим следующий класс (файл arr_class.php):

<?php
	class arr_class {
	
		public function getArr($k)
		{
				return explode('|',$k);
		}
		
		
	}

Опять же данный класс содержит всего один метод, который параметром принимает строку и разбивает ее в массив, по разделителю “|”. Для тестирования массивов в PHPUnit есть специальные методы. Поэтому давайте рассмотрим код файла test2.php, позволяющий выполнять тестирование массивов:

<?php
require_once 'PHPUnit/Autoload.php';
require_once 'arr_class.php';

class arr_classTest extends PHPUnit_Framework_TestCase {
	
	/**
	* @dataProvider providerGetArr
	*/
	public function testGetArr($key,$str) {
		$my = new arr_class();
		//$this->assertArrayHasKey($key,$my->getArr($str));
		//$this->assertContains($key,$my->getArr($str));
		//$this->assertContainsOnly('integer',$my->getArr($str));
		//$this->assertCount($key, $my->getArr($str));
	}
	
	public function providerGetArr ()
	{
		return array (
			array (3, 'ku|hello|white'),
			array (4, 'ku1|hello1|white1'),
			array (3, '2|2|2'),
		);
	}
}

Методы в классе я специально закомментировал, что бы можно было их использовать поочередно:

assertArrayHasKey($k, $arr) – проверяет, существует ли ключ $k, в массиве $arr.

assertContains($v, $arr) – проверяет существует ли элемент $v в массиве $arr.

assertContainsOnly(‘type’, $arr) — проверяет, содержат ли ячейки массива $arr, значения типа данных type.

assertCount($count,$arr) – проверяет, соответствует ли число $count, количеству элементов массива $arr.

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

4. Тестирование исключений

И последнее, что мы рассмотрим – это тестирование исключений. Давайте рассмотрим класс:

<?php
	class MyException extends Exception {};
	
	class ex_class {
		public function getEx($k)
		{
				if($k == 10) {
					throw new MyException('Wrong var');
				}
				else return true;
		}
	}
?>

Класс содержит всего один метод, который генерирует исключение, если переданный ему параметр равен 10. Теперь посмотрите на класс, с помощью которого можно проверить генерацию исключений:

<?php
require "PHPUnit/Autoload.php";
require "ex_class.php";

class ex_classTest extends PHPUnit_Framework_TestCase {
	
	protected $ob;
	
	protected function setUp() {
		$this->ob = new ex_class();
	}
	
	/**
	* @dataProvider providerGetEx
	* 
	*/
	public function testGetEx($key) {
		$this->setExpectedException("myException");
		$this->ob->getEx($key);
	}
	
	public function providerGetEx() {
		return array(
					array(3),
					array(1),
					array(10),
					array(3)
					);
	}
	
	protected function tearDown() {
		$this->ob = NULL;
	}
}
?>

Первое, что Вы наверное заметили, это то, что добавилось два метода:

setUp() – который выполняется перед тестом. То есть, используя данный метод можно выполнить различные подготовительные действия. К примеру, в нашем случае – создаем объект тестируемого класса и сохраняем в свойство $fixture.

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

Тестировать исключение можно при помощи метода setExpectedException(«myException») или необходимо указать перед тестируемым методом комментарий @expectedException MyException. Тест будет пройден успешно, если метод вернет исключение класса myException.

Вот и все, что я хотел сказать Вам по инструменту PHPUnit. Конечно, мы рассмотрели только основы, так как PHPUnit – это очень мощный и довольно сложный инструмент для тестирования кода. Но если он Вас заинтересовал, то продолжайте его дальнейшее изучение самостоятельно и применяйте изученное на практике.

Документация по PHPUnit содержится на данной странице: http://phpunit.de/manual/current/en/index.html

На этом давайте прощаться. Всего Вам доброго и удачного кодирования!!!

Курс по программированию на языке PHP

Изучите PHP с нуля до результата!

Смотреть курс

Метки: ,

Комментарии Вконтакте:

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

Комментарии (1)

  1. Денис

    Спасибо.
    а почему в строке

    $this->setExpectedException(«myException»);

    имя класса myException с маленькой буквы?

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

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

Можно использовать следующие HTML-теги и атрибуты: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Я не робот.

Spam Protection by WP-SpamFree