Пишем тест кода PHP с помощью Testify.php

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

Очень опасное заблуждение!

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

 

Введение в Testify.php

Testify - маленькая библиотека PHP для проверки кода, которая распространяется под лицензией GPL. Ее проектировали для простого и элегантного использования. Testify использует преимущества синтаксиса анонимных функций PHP 5.3 для облегчения определения тестов. Тесты логически группируются в кейсы. Наборы кейсов тестов  объединяются в комплекты. Рассмотрим, как маленькая библиотека может облегчить жизнь разработчика.

 

Что мы будем проверять?

В коротком примере мы создадим класс PHP для конвертации времени из формата, который обычно используется в базе данных (“15-10-2011 22:32″) в строку с относительным временем (“1 month ago”). Подобные классы нуждаются в тщательной объемной проверке, которая послужит отличной иллюстрацией использования Testify.

 

Класс RelativeTime

Существует несколько способов для вычисления относительного времени. Можно создать набор выражений if/else, который будет работать. Но такой код очень трудно поддерживать и для него очень высока вероятность появления ошибок. Мы будем использовать более элегантный способ. В его основе лежит факт, что каждый период времени состоит из четко определенного количества меньших периодов. То есть, один день состоит из 24 часов, один час - из 60 минут, а каждая минута содержит 60 секунд.

Здесь представлен скелет нашего класса:

class RelativeTime{
	
	// Названия периодов
	private $names = array('second','minute','hour','day','week','month','year');
	
	// Как много периодов содержится один в другом
	private $divisions = array(1,60,60,24,7,4.34,12); 
	
	private $time = NULL;
	
	public function __construct($timestr = NULL){
		// Можно передавать время при конструировании объекта
	}
	
	public function getOffsetFrom($timestr = NULL){

		// Данный метод вычисляет строку относительного времени

	}
	
	public function __toString(){
		
		// Подходящий метод магии PHP
		
	}
	
	private function timestampFromString($time){
		
		// Данный метод преобразует строку в корректное время в секундах
	}
}

А теперь перейдем к тестированию кода.

 

Использование Testify

Существует метод ведения процесса разработки кода, который называется "Разработка, ведомая тестированием" (TDD). В соответствии с данным процессом нужно сначала писать тест для получения лучшего результата. Рассмотрим, как использовать библиотеку в данном процессе.

Первый шаг - загрузить Testify. Затем извлечь из архива папку testify и включить файл в код PHP вместе с классом RelativeTime:

include 'RelativeTime.class.php';
include 'testify/testify.class.php';

Теперь создадим новый комплект тестов. Первым делом создаем экземпляр класса Testify.

$tf = new Testify("Testing RelativeTime with Testify");

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

$tf->test("Общая проверка класса", function($tf){
	$relative = new RelativeTime();
	
	// Еще не задано время.
	$tf->assert($relative == "Время не задано!");
	
	try{
		// Должно генерировать исключение
		$relative->getOffsetFrom();
		
		// Если вы оказались здесь, то тест провален:
		$tf->fail();
	}
	catch (Exception $e){
		$tf->assert($e->getMessage() == "Время не задано!");
	}
	
	try{
		// Должно работать
		$relative->getOffsetFrom("22-10-2011");
		$tf->pass();
	}
	catch (Exception $e){
		$tf->fail();
	}
	
});

Класс RelativeTime генерирует исключение, если мы запрашиваем строку времени, но еще не передали значение (либо в конструкторе, либо вызовом метода getOffsetFrom()). Но метод __toString не может генерировать исключение. Он только возвращает строку с текстом.

Здесь демонстрируется несколько методов для поддержки тестов  – assert(), pass() и fail().

Теперь добавим второй кейс тестов, который проверяет правильность возвращаемых строк.

$tf->test("Проверка функционала относительного времени", function($tf){
	
	// Проверяем класс с установленным временем
	$relative = new RelativeTime(timestamp(time()-130));
	
	// Проверяем метод getOffsetFrom 
	$tf->assert($relative->getOffsetFrom() == "2 minutes ago");

	// Проверяем конверсию __toString
	$tf->assert($relative == "2 minutes ago");
	
	// Быстрая проверка
	$tf->assert( new RelativeTime( time()) 			== "just now");
	$tf->assert( new RelativeTime( time()-11)		== "11 seconds ago");
	$tf->assert( new RelativeTime( time()-59)		== "59 seconds ago");
	$tf->assert( new RelativeTime( time()-60)		== "1 minute ago");
	$tf->assert( new RelativeTime( time()-89)		== "1 minute ago");
	$tf->assert( new RelativeTime( time()-90)		== "2 minutes ago");
	$tf->assert( new RelativeTime( time()-30*60)		== "30 minutes ago");
	$tf->assert( new RelativeTime( time()-59*60)		== "59 minutes ago");
	$tf->assert( new RelativeTime( time()-60*60)		== "1 hour ago");
	$tf->assert( new RelativeTime( time()-90*60)		== "2 hours ago");
	$tf->assert( new RelativeTime( time()-86400) 		== "1 day ago");
	$tf->assert( new RelativeTime( time()-3*86400)		== "3 days ago");
	$tf->assert( new RelativeTime( time()-9*86400)		== "1 week ago");
	$tf->assert( new RelativeTime( time()-29*86400)		== "4 weeks ago");
	$tf->assert( new RelativeTime( time()-31*86400)		== "1 month ago");
	$tf->assert( new RelativeTime( time()-100*86400)	== "3 months ago");
	$tf->assert( new RelativeTime( time()-350*86400)	== "12 months ago");
	$tf->assert( new RelativeTime( time()-365*86400)	== "1 year ago");
	$tf->assert( new RelativeTime( time()-20*365*86400)	== "20 years ago");
	
});

// Вспомогательная функция для конструирования строки времени
function timestamp($unixTime){
	return date('r',$unixTime);
}

Отлично! Теперь вызываем метод run() и получаем отчет об ошибке теста.

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

class RelativeTime{
	
	// Названия периодов
	private $names = array('second','minute','hour','day','week','month','year');
	
	// Как много периодов содержится один в другом
	private $divisions = array(1,60,60,24,7,4.34,12); 
	
	private $time = NULL;
	
	public function __construct($timestr = NULL){
		// Можно передавать время при конструировании объекта
		$this->timestampFromString($timestr);
	}
	
	public function getOffsetFrom($timestr = NULL){

		// Данный метод вычисляет строку относительного времени

		$this->timestampFromString($timestr);
		
		if(is_null($this->time)){
			throw new Exception("Timestamp not specified!");
		}
		
		$time = $this->time;
		$name = "";
		
		if($time < 10){
			return "just now";
		}
		
		for($i=0; $i<count($this->divisions); $i++){
			if($time < $this->divisions[$i]) break;
			
			$time = $time/$this->divisions[$i];
			$name = $this->names[$i];
		}
		
		$time = round($time);
		
		if($time != 1){
			$name.= 's';
		}
	
		return "$time $name ago";
	}
	
	public function __toString(){
		
		// __toString не может генерировать исключение
		
		try{
			return $this->getOffsetFrom();
		}
		catch(Exception $e){
			return $e->getMessage();
		}
	}
	
	private function timestampFromString($time){
		
		if(is_numeric($time)){
			// Формат времени unix (количество секунд, прошедших с 1 января 1970)
			$this->time = time() - $time;
		}
		else if(is_string($time)){
			// Время строкой
			$this->time = time() - strtotime($time);
		}
	}
}

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

 

Заключение

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

Источник: http://feedproxy.google.com/~r/ruseller/CdHX/~3/YxsxAPbYJcg/lessons.php

Читать комменты и комментировать

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



Защитный код
Обновить

Пишем тест кода PHP с помощью Testify.php | | 2012-06-19 12:01:19 | | Статьи Web-мастеру | | Если вы только недавно начали участвовать в разработке веб проектов, то, скорее всего, тестирование кода не имеет высокого приоритета в вашем списке важных дел. Вы создаете то, что требуется, | РэдЛайн, создание сайта, заказать сайт, разработка сайтов, реклама в Интернете, продвижение, маркетинговые исследования, дизайн студия, веб дизайн, раскрутка сайта, создать сайт компании, сделать сайт, создание сайтов, изготовление сайта, обслуживание сайтов, изготовление сайтов, заказать интернет сайт, создать сайт, изготовить сайт, разработка сайта, web студия, создание веб сайта, поддержка сайта, сайт на заказ, сопровождение сайта, дизайн сайта, сайт под ключ, заказ сайта, реклама сайта, хостинг, регистрация доменов, хабаровск, краснодар, москва, комсомольск |
 
Поделиться с друзьями: