От началото на месеца, голяма част от работата ми включваше почти изцяло пренаписване на повечето 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');


