4 поста с таг phpunit

Feb 13

Тази седмица маркира края на изпитната ми сесия в университета, затова все още имам към 232 не прочетени статии в Google reader. Но пак си мисля, че събрах интересни неща за тази седмица.

Понеделник 08.02.2010

EdgeRails.Info – Блога Ryan’s Scraps се публикуваше детайлна информация за всяко ново нещо в Rails . И от там съм научил толкова много за Rails, колкото от никъде другаде (изключвам railscasts). Сега Ryan Daigle е решил да премести цялата Edge Rails секция в ново създадения EdgeRails.Info. Така че това се очертава да е много важен сайт от сега на татък.

Javascript quizJuriy Zaytsev ( или kangax ) е направил много добър тест за javascript. Който е доста по-труден от този на Dmitry Baranovsky, за който бях писал преди две седмици. Аз лично имах 3 грешни отговора, което не беше никак добре, но бързо си разбрах грешките.

Вторник 09.02.2010

Answering the Juriy Zaytsev JavaScript Quiz – за тези, които много са се затруднили с теста на kangax, ето ги и отговорите с обяснения.

Crockford on JavaScript — Chapter 2: And Then There Was JavaScript – Това е продължението на “Crockford on JavaScript The Early Years“. Много добре се преплита миналото и бъдещето на JavaScript.

Сряда 10.02.2010

Why Does SproutCore Use Absolute Positioning to Layout Views? – Заслужава си да се прочете, независимо от това дали използвате или не SproutCore. Защото поста спокойно да се отнесе към доста други подобни библиотеки.

За пръв път видях този блог тази седмица и като се зачетох в предишни постове, го маркирам като един от задължителните четива за хора който искат да работят със  SproutCore. Въпреки че аз не съм от тези хора, следя много от близо SproutCore.

Четвъртък 11.02.2010

Testing Code That Uses Singletons – Sebastian Bergmann е написал доста обширна статия за това как да тестваме Singleton класове в PHP с PHPUnit.

В Четвъртък ми попадна ( мисля че от twitter ) и този gist – http://gist.github.com/289467 :)
Лично аз бих написал като “много мързелив javascriptер” бих го написал:

(function(x){ return !x ? 1 : x * arguments.callee(x-1); })(5);

Лошото е че arguments.callee си отива. Ето едно наистина добро обяснение защо – Web Reflection: ES5 arguments and callee, I was wrong! ( между другото, това е още един задължителен блог за всяка javascript нинджа )

Петък 12.02.2010

Ext JS is Migrating to Git – Още едно доказателство за това, че git и github в момента са номер едно. Аз ги използвам от половин година вече и лоша дума за тях не мога да кажа.

Sep 23

От началото на месеца, голяма част от работата ми включваше почти изцяло пренаписване на повечето unit тестове на основните ми PHP библиотеки. Основната причина за това беше че повечето тестове бяха на повече от година, като през този период само съм добавял код за нови методи. И през това време тестове станах доста големи и тежки затова се наложи това малко “освежаване”

Основното нещо което исках да тествам по-добре този път бяха ‘protected’ методите на голяма част от класовете. Примерно основния ми Controller клас има само 2 публични метода и всичко друго е protected. Защото идеята на този клас  е да се ползва “отвътре”.

Преди какво правех? Просто си дефинирах един помощен decorator клас през който виках protected методите. Обаче това винаги ми се е струвало доста “мръсно” решение.  Затова реших потърся дали някой не се е сетил нещо по-добро от мен. И затова потърсих -  “php testing protected methods“. И от там намерих този пост – Testing protected Methods in Unit Tests от Frontalaufprall. Което на този етап ми се вижда перфектното решение. И така с много малко промени се получи този код с който тестването на protected методи става изключително лесно:

function getProtectedMethodsProxy($className){
	$proxyClassName = $className . 'PrivateMethodsProxy';

	if (!class_exists($proxyClassName, false)){
		eval('
			class ' . $proxyClassName . ' extends ' . $className . ' {
				public function __call($method, $arguments){
					$method = str_replace("_", "", $method);

					if (!method_exists($this, $method)){
						return parent::__call($method, $arguments);
					}

					return call_user_func_array(array($this, $method),  $arguments);
				}
			}
		');
	}

	if (func_num_args() == 1){
		return new $proxyClassName();
	}

	$class = new ReflectionClass($proxyClassName);
	return $class->newInstanceArgs(array_slice(func_get_args(), 1));
}

Начин на ползване:

$class = getProtectedMethodsProxy('Controller_Action');
$class->_redirect('http://next.pixeldepo.com');
// и вариант с параметри в конструктора
$class = getProtectedMethodsProxy('SomeClass', 1, 2, 3); // new SomeClass(1, 2, 3);
$class->_someVeryProtectedMethod('test');

Все пак eval не винаги е толкова лош :)

Sep 17

Преди време писах за PHP тестване в – PHP Unit testing. И сега искам да споделя един метод на тестване, с който използвах вече няколко пъти, което ми спести писане и като цяло се получи много добре.

Наскоро имах да тествам един базов клас и неговите наследници. Базовия клас се казва Session_Base и представлява абстрактен клас, в който съм си дефинирал основните операции за работа със сесии – set, unset, get, cut ( това е смесица между get и unset ), start, stop, fingerprint и други. Имам и няколко класа които го наследяват:

  • Session_Default – това си е просто нормалната php сесия и $_SESSION
  • Session_File – разликата с Session::Default е само че, този файл се грижи за записване и четене на session файловете
  • Session_Database – Session::File но за база данни
  • Session_Custom – Това е версията на стария ми php session клас ( много стара версия може да му видите на http://www.phpclasses.org/browse/package/2879.html )

Така това прави най-малко 4-5 TestCases. които във своята основа са едни и същи тест. В който се проверяват get/set/unset….open/write/read….

Затова реших да направя така:

// Test_TestCase си е един мой клас в който си слагам помощни работи и екстендва PHPUnit_Framework_TestCase
abstract class SessionBaseTest extends Test_TestCase {
private $sess;
function setUp();

function tearDown(){
$this->sess = null;
}

function testSettingVariable() { /* .... */ }
function testGettingVariable() { /* .... */ }
/* oще тестове */
}

Това ще ми служи като база за останалите тестове на сесията. И при едно наследяване PHPUnit ще изпълни и методите (тестовете).

// Test_TestCase си е един мой клас в който си слагам помощни работи и екстендва PHPUnit_Framework_TestCase
abstract class SessionDefaultTest extends Test_TestCase {
private $sess;
function setUp(){
$this->sess = new Session_Default();
}

// тестове специално към Session_Default();
}

Подобни тест класове си правя и за останалите класове. setUp() е абстрактен за да може в $this->sess да се сложи съответния клас.

Подобен метод използвах и в друга ситуация, разликата беше че имах редица от наследяващи се класове – RecordValidator -> FormValidator -> ActiveRecordValidator като всеки клас добавя нова функционалност, но основните действия, не трябваше да се променят. Тук направих TestCase за RecodValidator, после TestCase- за FormValidator го наследи и накрая ActiveRecordValidator наследи FormValidatorТest. Така си хванах сумати грешки и си спестих излишно писане на код ;)

Sep 01

Днес(т.е. на 27, просто от тогава този пост седи във draft-a) прочетох това:

Database helper for PHPUnit

Във него се показва интересен метод за работа със PHPUnit и тестване на база данни. Този пост, ме “вдъхнови” и мен да споделя, как аз работя със PHPUnit.
Първо директорийната структура. В една папка тест имам следните неща:

  • benchmarks/ – съдържа различни benchmark тестове ( за тях някои друг път по-подробно)
  • fixtures/ – fixtures на тестовете
  • reports/ – code coverage докладите на xdebug
  • unit/ – самите unit тестове
  • enviroment.php – различни настройки

Под папките на unit, отговарят на разлините testcase -ове. Например testcase за ActiveRecord::Relations::Many се намира в unit/ActiveRecord/Relations/ActiveRecordRelationManyTest.php. Това което е по-интересно в случая е, че в повечето папките имам един файл: setup.php този файл се изпълнява преди тестовете от съответния testcase да се активират. Идеята му е се заредят класовете, файловете, да се изчисти базата данни преди тестване.

За тестове съм си направил едни клас Test_TestCase който наследява PHPUnit_Framework_TestCase и в него съм си добавил няколко помощни метода за тестване.

И накрая имам един клас Test_Runner който стартира тестовете. Кода на Test_Runner може да намерите тук.

Кода се използва така:

// константите DS и TESTS_DIR се използват при инициализация на Test_Runner
define('DS', DIRECTORY_SEPARATOR);
define('TESTS_DIR',  		ROOT_DIR . DS . 'test' . DS . 'unit');

$r = new Test_Runner();
$r->run($options);

Също така използвам и 2-3 php скриптчета за генериране на скелета за тест класа, директориите, setup.php файловете и други.

По принцип, не харесвам много PHPUnit, но за нещастие няма за сега по-добро нещо за тестове в PHP света, до колкото знам. A и ако добре се документира и структурира тест кода, нещата стават доста по-поносими.

Ако някои има идеи и съвети за PHPUnit или тестването като цяло, да се чувства поканен да остави коментар :)