如果该函数应该杀死PHP,你如何使用PHPUnit来测试函数?

时间:2009-08-28 15:37:30

标签: php unit-testing phpunit

基本上我有一个名为killProgram的类的方法,它用于发送hTTP重定向然后杀死PHP。

我该如何测试?当我运行phpunit时,它不返回该测试的任何内容,并完全关闭。

现在我正在考虑让killProgram函数抛出一个不应该被处理的异常,这将允许我断言抛出异常。

有更好的方法吗?

6 个答案:

答案 0 :(得分:23)

由于每个测试都是由同一个PHPUnit进程运行的,如果你在PHP代码中使用exit / die,你会杀死所有东西 - 正如你注意到的那样^^

所以,你必须找到另一种解决方案,是的 - 就像回归而不是死亡一样;或抛出异常(您可以测试一些经过测试的代码是否抛出了预期的异常)

也许PHPUnit 3.4及其--process-isolation切换(请参阅Optionally execute each test using a separate PHP process可能帮助(没有让所有事情都死亡),但你仍然不愿意如果PHPUnit没有得到控制权,那么就无法获得测试结果。

我有几次这个问题;通过返回而不是死亡来解决它 - 如果需要,甚至返回几次,以便在调用堆栈中返回“足够高”^^
最后,我想我的应用程序中没有任何“死”......当考虑MVC时,可能会更好。顺便说一句。

答案 1 :(得分:20)

这显然是一个老问题,但我的建议是将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();
    }
}

我没有测试过代码,但应该非常接近工作状态。

答案 2 :(得分:14)

无需更改代码只是为了能够对其进行测试,您只需使用set_exit_overload()(由来自同一作者的test_helpers提供的PHPUnit)。

答案 3 :(得分:7)

我意识到你已经接受了这个答案,这是一个老问题,但我认为这可能对某人有用,所以这里有:

您可以使用die()(或您自己的异常类),而不是使用throw new RuntimeException(),这也将暂停程序执行(尽管以不同的方式)并使用PHPUnit的{{3}抓住它。如果您希望在遇到异常时将脚本发送到die(),请在用户级别打印绝对没有内容,请查看setExpectedException()

具体来说,我正在考虑将set_exception_handler() - 调用放入测试不使用的引导程序文件的情况,因此无论方案如何,处理程序都不会在那里触发,所以没有任何东西干扰PHPUnit的本机异常处理。

答案 4 :(得分:4)

这与我已经获得一些遗留代码以通过测试的一系列问题有关。所以我想出了一个像这样的Testable类......

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

现在我只需用Testable :: exitphp()替换对exit()的调用。

如果它正在测试中我只是定义UNIT_TESTING,在生产中我没有。看起来像一个简单的模拟。

答案 5 :(得分:0)

您可以杀死脚本或引发异常,具体取决于环境变量的值...

因此,您在生产中会杀死应用程序或在测试环境中抛出异常。

任何呼叫死亡或退出的请求,都会杀死整个过程...

这本来应该是评论,但我无法评论我的声誉点的水平。