Quantcast
Channel: सत्यं वद धर्मं चर » Vladimir
Viewing all articles
Browse latest Browse all 30

Запуск тестов PHPT при помощи PHPUnit

$
0
0

Обход подводных камней при наличии тестов, требующих -

(известный как PHP Testing Framework) — лёгкий фреймворк для тестирования, используемый для тестирования самого PHP, а также расширений PECL и PEAR (это de facto стандарт для тестирования PECL и PEAR). Одно из самых больших его достоинств — простота написания тестов (пример истории успеха).

Иногда в проекте используется несколько фреймворков для тестирования (например, для модульного тестирования и PHPT для (быстрого) тестирования регрессий); в этом случае бывает удобным настроить запуск всех тестов из одного места, а ещё лучше — полную интеграцию тестов.

В PHPUnit есть два полезных класса: PHPUnit_Extensions_PhptTestSuite и PHPUnit_Extensions_PhptTestCase. Первый предназначен для создания набора тестов (test suite) из файлов *.phpt заданного каталога. Второй класс является обёрткой над тестом PHPT.

В большинстве случаев интеграция будет заключаться в написании класса, подобного данному:

class PHPTTestSuite extends PHPUnit_Framework_TestCase
{
    public static function suite()
    {
        return new PHPUnit_Extensions_PhptTestSuite('/path/to/tests');
    }
}

и заданию набора тестов в файле конфигурации:

    <testsuite name="PHPT Test Suite">
        <file>path/to/PHPTTestSuite.php</file>
    </testsuite>

Или вообще такой конструкцией (не требует дополнительного класса):

<testsuite name="PHPT">
    <directory suffix=".phpt">path/to/tests</directory>
</testsuite>

И в большинстве случаев это будет работать.

Тем не менее, есть один большой подводный камень — если тестам PHPT требуется CGI, то без танцев с бубном не обойтись.

Приведём пример:

--TEST--
PHPUnit + CGI: FAIL
--GET--
a=duniyā
--FILE--
<?php echo "Hailō ", $_GET['a'], PHP_EOL; ?>
--EXPECT--
Hailō duniyā
<phpunit>
    <testsuites>
        <testsuite name="PHPT">
            <directory suffix=".phpt">./</directory>
        </testsuite>
    </testsuites>
</phpunit>

Запускаем: phpunit -c phpunit.xml

Получаем:

PHPUnit 3.6.10 by Sebastian Bergmann.

Configuration read from /home/vladimir/cgitest/phpunit.xml

F

Time: 1 second, Memory: 3.75Mb

There was 1 failure:

1) /home/vladimir/cgitest.phpt
--- Expected
+++ Actual
@@ @@
-Hailō duniyā
+


FAILURES!
Tests: 1, Assertions: 1, Failures: 1.

Изучение внутренностей PHPUnit показало, что проблема (скорее всего) лежит где-то внутри PEAR_RunTest:

        if (OS_WINDOWS && isset($section_text['RETURNS'])) {
            ob_start();
            system($cmd, $return_value);
            $out = ob_get_contents();
            ob_end_clean();
            $section_text['RETURNS'] = (int) trim($section_text['RETURNS']);
            $returnfail = ($return_value != $section_text['RETURNS']);
        } else {
echo $cmd, "\n";
            $returnfail = false;
            $stdin = isset($section_text['STDIN']) ? $section_text['STDIN'] : null;
            $out = $this->system_with_timeout($cmd, $env, $stdin);
print_r($out);
            $return_value = $out[0];
            $out = $out[1];
        }

При запуске получим что-то такое:

Configuration read from /home/vladimir/cgitest/phpunit.xml

php-cgi -d "include_path=.:/usr/share/php:/usr/share/pear" -d "coverage=" -d "output_handler=" -d "open_basedir=" -d "safe_mode=0" -d "disable_functions=" -d "output_buffering=Off" -d "display_errors=1" -d "log_errors=0" -d "html_errors=0" -d "track_errors=1" -d "report_memleaks=0" -d "report_zend_debug=0" -d "docref_root=" -d "docref_ext=.html" -d "error_prepend_string=" -d "error_append_string=" -d "auto_prepend_file=" -d "auto_append_file=" -d "magic_quotes_runtime=0" -d "xdebug.default_enable=0" -d "allow_url_fopen=1" -d "error_reporting=22527" -f '/home/vladimir/cgitest/test.php' 2>&1
Array
(
    [0] => 127
    [1] => sh: 1: php-cgi: not found

)
F

Видим, что php-cgi где-то потерялся, хотя из командной строки его вызвать можно.

Насколько я могу судить, это происходит из-за того, что $_ENV['PATH'] не установлен, ибо $_ENV['PATH'] = $_SERVER['PATH']; быстро всё решило.

UPDATE: проблема оказалась в настройках PHP: для того, чтобы всё работало, в variables_order должно присутствовать E (например, variables_order = EGPCS) — причём для CLI, так как PHPUnit запускается из командной строки. Но указывать пользователю, что нужно изменить в php.ini — не comme il faut, по моему мнению.

Поэтому для исправления ситуации можно поступить так:

<?php

class PHPTTestSuite extends PHPUnit_Framework_TestCase
{
    public static function suite()
    {
        if (empty($_ENV)) {
            if (isset($_SERVER['PATH'])) {
                $_ENV['PATH'] = $_SERVER['PATH'];
            }
            else {
                $_ENV['PATH'] = getenv('PATH');
            }
        }

        return new PHPUnit_Extensions_PhptTestSuite(__DIR__);
    }
}
<phpunit>
    <testsuites>
        <testsuite name="PHPT Test Suite">
            <file>./PHPTTestSuite.php</file>
        </testsuite>
    </testsuites>
</phpunit>

После запуска получим

PHPUnit 3.6.10 by Sebastian Bergmann.

Configuration read from /home/vladimir/cgitest/phpunit.xml

.

Time: 0 seconds, Memory: 4.25Mb

OK (1 test, 1 assertion)

Но и это ещё не всё ©

Дело в том, что PEAR_RunTest не полностью поддерживает спецификацию PHPT. В частности, php-cgi будет использован только если в файле присутствует хотя бы одна из секций POST, POST_RAW, UPLOAD, GET, COOKIE, EXPECTHEADERS (UPLOAD вообще нет в спецификации). Секции PUT, GZIP_POST, DEFLATE_POST, CGI не поддерживаются и тесты с такими секциями, скорее всего, работать не будут.

Простой пример:

--TEST--
Require CGI SAPI: FAIL
--CGI--
--FILE--
<?php echo PHP_SAPI, PHP_EOL; ?>
--EXPECTREGEX--
^cgi(.*+)$
PHPUnit 3.6.10 by Sebastian Bergmann.

Configuration read from /home/vladimir/cgitest/phpunit.xml

F.

Time: 1 second, Memory: 4.25Mb

There was 1 failure:

1) /home/vladimir/cgitest/cgi.phpt
--- Expected
+++ Actual
@@ @@
-^cgi(.*+)$
+cli


FAILURES!
Tests: 2, Assertions: 2, Failures: 1.

Поэтому в случае использования тестов с такими секциями, несовместимые тесты придётся пропустить:

class PHPTTestSuite extends PHPUnit_Framework_TestCase
{
    public static function suite()
    {
        if (empty($_ENV)) {
            if (isset($_SERVER['PATH'])) {
                $_ENV['PATH'] = $_SERVER['PATH'];
            }
            else {
                $_ENV['PATH'] = getenv('PATH');
            }
        }

        $facade = new File_Iterator_Facade;
        $files  = $facade->getFilesAsArray(__DIR__, '.phpt');

        $suite = new PHPUnit_Framework_TestSuite();

        foreach ($files as $file) {
            $c = file_get_contents($file);
            if (!preg_match('/^--(?:PUT|(?:GZIP|DEFLATE)_POST|CGI)--$/m', $c)) {
                $suite->addTestFile($file);
            }
        }

        return $suite;
    }
}

В идеале эта функциональность должна быть в PEAR_RunTest, но пока её там нет, приходится обходиться подручными средствами.

© 2013 सत्यं वद धर्मं चर. Все права защищены. Перепубликация материалов без разрешения автора запрещена.

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


Viewing all articles
Browse latest Browse all 30

Latest Images

Trending Articles





Latest Images