Все, кто разрабатывает на php, да и вообще на любом другом языке программирования с нечеткой типизацией, сталкивались с подобной проблемой:
Или даже такой:
В ходе разработки одного крупного проекта пришлось заняться тестированием написанных методов на правильно подданные параметры.
В моем случае я тестировал класс и контракт для него, но идеология тестирования одна и та же.
Допустим, есть функция которая привыкла принимать входной параметр массив, обрабатывать некоторые элементы.
Например:
Я написал простенький класс, который помогает в тестировании функций, он генерирует рандомные данные, начиная от int закачивая null-ом.
Вот его код:
Он очень простенький, но зато сохраняет очень много времени.
Пример использования:
Резюмируя, могу сказать, что метод тестирования который я «навелосипедил» называется Fuzzing.
Пара ссылок по теме:
www.vr-online.ru/?q=content/fuzzing-tehnologija-ohoty-za-bagami-752
wiki.xakep.ru/Default.aspx?Page=fuzzing&AspxAutoDetectCookieSupport=1
ps Мой первый топик на хабре, немного сумбурный и наверное много ошибок, прошу сильно не пинать, все замечания учту и сделаю его лучше.
upd добавил ссылку на vr-online.ru
upd2 немного переписал класс, учитывая замечания из коментариев
PHP Notice: Undefined index: test in /var/www/Testing.php on line 171 PHP Notice: Undefined index: test2 in /var/www/Testing.php on line 171
Или даже такой:
PHP Fatal error: Cannot use object of type stdClass as array in /var/www/Testing.php on line 171
В ходе разработки одного крупного проекта пришлось заняться тестированием написанных методов на правильно подданные параметры.
В моем случае я тестировал класс и контракт для него, но идеология тестирования одна и та же.
Допустим, есть функция которая привыкла принимать входной параметр массив, обрабатывать некоторые элементы.
Например:
PHP Warning: mysql_affected_rows() expects parameter 1 to be resource, string given in /var/www/Testing.php on line 177
Я написал простенький класс, который помогает в тестировании функций, он генерирует рандомные данные, начиная от int закачивая null-ом.
Вот его код:
class tester { public static $useRandom = true; public static $randMin = 1; public static $randMax = 50; public static $stringDefaultPreffix = 'string_'; public static $mode = 'real'; const T_INTEGER = 0; const T_STRING = 1; const T_ARRAY = 2; const T_OBJECT = 3; const T_BOOLEAN = 4; const T_FUNCTION = 5; const T_NULL = 6; /** * Настройка "рандомайзера" * чтобы не переписывать код по несколько раз для разных тестов */ public static $allowedTytes = array(self::T_INTEGER,self::T_STRING); public static function getRand() { $dice = array_rand(self::$allowedTytes, 1); /* * если честно то какой то топорный механизм декларации методов =( * мне не нравится */ switch ($dice) { /** * пусть будет int */ case self::T_INTEGER : return self::getInt(); break; /** * а это строка */ case self::T_STRING: return self::getString(); break; /** * массив */ case self::T_ARRAY: return self::getArray(); break; /** * ну ладно еще и объект */ case self::T_OBJECT: return self::getObject(); break; /** * Еще и були! */ case self::T_BOOLEAN: return self::getBoolean(); break; /** * функция, чем черт не шутит? */ case self::T_FUNCTION: return self::getFunction(); break; /** * null? */ case self::T_NULL: return self::getNull(); break; default: return true; break; } } /** * получение null * @static * @return null */ public static function getNull() { return null; } /** * получение массива * @static * @return array */ public static function getArray() { $array = array(); $arrayLength = mt_rand(self::$randMin, self::$randMax); while (count($array) < $arrayLength) { /** * self::getRand(); почему то ошибка сегментирования =( * а как хотелось бы чтоб все влезало в память=) */ $array[] = mt_rand(self::$randMin, self::$randMax); } return $array; } /** * получение объекта * @static * @return stdClass */ public static function getObject() { return new stdClass(); } /** * получение булевого значения * @static * @param bool $default * @return bool */ public static function getBoolean($default = true) { if (self::$useRandom) { return (mt_rand(0, 1) ? true : false); } else { return $default; } } /** * получение целого числа * @static * @param int $default * @return int */ public static function getInt($default = 42) { if (self::$useRandom) { return mt_rand(self::$randMin, self::$randMax); } else { return $default; } } /** * генерация рандомной строки * @static * @param string $default * @return string */ public static function getString($default = 'string_1234567') { if (self::$useRandom) { return uniqid(self::$stringDefaultPreffix); } else { return $default; } } /** * создаем функцию * @static * @return string */ public static function getFunction() { /** * честно, копипаст с * http://php.net/manual/en/function.create-function.php */ return create_function('$a,$b', 'return "ln($a) + ln($b) = " . log($a * $b);'); } /** * наш еррор хендлер, можно отнаследоваться и поставить свой * @param $errno * @param $errstr * @param $errfile * @param $errline * @return bool */ public function errorHandler($errno, $errstr, $errfile, $errline) { echo '-----ERROR----', PHP_EOL; echo $errstr, PHP_EOL; echo 'Line:', $errline, ' in file: ', $errfile, PHP_EOL; echo '-------------', PHP_EOL; return true; } /** * активация встроенное ерорхендлера * @static * @return void */ public static function setErrorHandler() { set_error_handler(array(new self(), "errorHandler")); } /** * тестирование класса * @static * @param string $className * @param null $method * @return void */ public static function test($className = 'stdClass', $method = null) { if (class_exists($className, true)) { $obj = new ReflectionClass($className); /** * берем список всех публичных методов которые будем вызывать */ $methods = $obj->getMethods(ReflectionMethod::IS_PUBLIC); foreach ($methods as $method) { $argsCount = $method->getNumberOfParameters(); $args = array(); for ($i = 0; $i < $argsCount; $i++) { $args[] = self::getRand(); } if ($method->isStatic()) { $result = call_user_func(array($className, $method->getName()), $args); } else { $obj = new $className(); $result = call_user_func(array($obj, $method->getName()), $args); } } } } }
Он очень простенький, но зато сохраняет очень много времени.
Пример использования:
class badWritenClass { public function testFunc1($param) { echo count($param),PHP_EOL; } public function testFunc2($param) { $calcVar = $param['test'] / $param['test2'] * 50; echo $calcVar ,PHP_EOL; } public static function goodWritenFunc($param) { if (is_array($param) && isset($param['name'])) { echo 'Hello ', $param['name'],PHP_EOL; } else { echo 'Hello Guest!',PHP_EOL; } } } function testFunc1($param) { echo count($param) ,PHP_EOL; } function testFunc2($param) { $calcVar = $param['test'] + $param['test2'] * 50; echo $calcVar ,PHP_EOL; } /** * установка хендлера встроенного в класс */ tester::setErrorHandler(); tester::$allowedTytes = array(tester::T_INTEGER, tester::T_STRING, tester::T_ARRAY, tester::T_OBJECT, tester::T_BOOLEAN, tester::T_FUNCTION, tester::T_NULL); /** * тестим какие функции */ testFunc1(tester::getRand()); testFunc2(tester::getRand()); /** * тестим целый класс */ tester::test('badWritenClass');
Резюмируя, могу сказать, что метод тестирования который я «навелосипедил» называется Fuzzing.
Пара ссылок по теме:
www.vr-online.ru/?q=content/fuzzing-tehnologija-ohoty-za-bagami-752
wiki.xakep.ru/Default.aspx?Page=fuzzing&AspxAutoDetectCookieSupport=1
ps Мой первый топик на хабре, немного сумбурный и наверное много ошибок, прошу сильно не пинать, все замечания учту и сделаю его лучше.
upd добавил ссылку на vr-online.ru
upd2 немного переписал класс, учитывая замечания из коментариев
