Как вы используете PHPUnit для проверки функции, если эта функция должна убить PHP? - PullRequest
34 голосов
/ 28 августа 2009

По сути, у меня есть метод класса с именем killProgram, который предназначен для отправки перенаправления hTTP, а затем для уничтожения PHP.

Как я должен это проверить? Когда я запускаю phpunit, он ничего не возвращает для этого теста и закрывается полностью.

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

Есть ли лучший способ?

Ответы [ 5 ]

23 голосов
/ 28 августа 2009

Поскольку все тесты выполняются одним и тем же процессом PHPUnit, если вы используете exit / die в своем PHP-коде, вы убьете все - как вы заметили ^^

Итак, вам нужно найти другое решение, да - как возвращение вместо смерти; или сгенерировать исключение (вы можете проверить, не вызвал ли какой-либо протестированный код ожидаемое исключение) .

Может быть, PHPUnit 3.4 и его переключатель --process-isolation (см. При желании выполнить каждый тест с использованием отдельного процесса PHP ) может помочь (не умирая) , но вы все равно не сможете получить результат теста, если PHPUnit не вернет элемент управления.

У меня была эта проблема пару раз; решил это, вернувшись вместо смерти - даже возвращаясь несколько раз, если нужно, чтобы вернуться «достаточно высоко» в стек вызовов ^^
В конце концов, я полагаю, что в моем приложении больше нет "кубика" ... Наверное, лучше подумать о MVC, кстати.

21 голосов
/ 05 февраля 2014

Это, очевидно, старый вопрос, но я предлагаю перенести код, который die(), в отдельный метод, который затем можно смоделировать.

Например, вместо этого:

class SomeClass
{
    public function do()
    {
        exit(1);
        // or
        die('Message');
    }
}

сделать это:

class SomeClass
{
    public function do()
    {
        $this->terminate(123);
        // or
        $this->terminate('Message');
    }

    protected function terminate($code = 0)
    {
        exit($code);
    }

    // or 
    protected function terminate($message = '')
    {
        die($message);
    }
}

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

Ваш тест будет выглядеть примерно так:

class SomeClassTest extends \PHPUnit_Framework_TestCase
{

    /**
     * @expectedExceptionCode 123
     */
    public function testDoFail()
    {
        $mock = $this->getMock('SomeClass');
        $mock->expects($this->any())
             ->method('terminate')
             ->will($this->returnCallback(function($code) {
                 throw new \Exception($code);
             }));

        // run to fail
        $mock->do();
    }
}

Я не тестировал код, но должен быть довольно близко к рабочему состоянию.

14 голосов
/ 29 февраля 2012

Нет необходимости изменять код, просто чтобы иметь возможность его протестировать, вы можете просто использовать set_exit_overload() (предоставляется test_helpers от того же автора, что и PHPUnit).

7 голосов
/ 21 апреля 2010

Я понимаю, что вы уже приняли ответ на этот вопрос, и это старый вопрос, но я полагаю, что это может быть полезно для кого-то, так что здесь:

Вместо использования die() вы можете использовать throw new RuntimeException() (или собственный класс исключений), который также остановит выполнение программы (хотя и другим способом) и использовать PHPUnit setExpectedException() чтобы поймать это. Если вы хотите, чтобы ваш сценарий die() при обнаружении этого исключения, абсолютно ничего не печатая на уровне пользователя, взгляните на set_exception_handler().

В частности, я имею в виду сценарий, в котором вы бы поместили set_exception_handler() -call в файл начальной загрузки, который не используют тесты, поэтому обработчик не будет запускаться там независимо от сценария, так что ничего мешает нативной обработке исключений в PHPUnit.

4 голосов
/ 13 декабря 2013

Это относится к ряду проблем, с которыми я сталкивался, когда получал какой-то устаревший код для прохождения теста. Итак, я придумал класс Testable, подобный этому ...

class Testable {
   static function exitphp() {
      if (defined('UNIT_TESTING')) {
         throw new TestingPhpExitException();
      } else {
         exit();
      }
   }
}

Теперь я просто заменяю вызовы exit () на Testable :: exitphp ().

Если это тестируется, я просто определяю UNIT_TESTING, а в производстве - нет. Похоже на простой макет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...