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

Zee*_*cer 35 php phpunit unit-testing

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

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

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

有没有更好的办法?

Pas*_*TIN 23

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

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

也许PHPUnit 3.4和它的--process-isolation开关(参见使用单独的PHP进程可选地执行每个测试)可能有所帮助(通过不会让所有东西都死掉),但如果PHPUnit没有得到,你仍然无法获得测试结果控制回来.

我有几次这个问题; 通过返回,而不是垂死解决了这个问题-即使回国几次,如果需要的话,回去"足够高",在调用堆栈^^
最后,我想我没有在我的应用程序的任何"死"了. ..当考虑MVC时,它可能更好,顺便说一句.


And*_*ris 22

这显然是一个老问题,但我的建议是将代码移动die()到一个单独的方法,然后你可以模拟.

举个例子,而不是这个:

class SomeClass
{
    public function do()
    {
        exit(1);
        // or
        die('Message');
    }
}
Run Code Online (Sandbox Code Playgroud)

做这个:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

这样您就可以轻松地模拟该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();
    }
}
Run Code Online (Sandbox Code Playgroud)

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


小智 14

没有必要更改代码只是为了能够测试它,你可以简单地使用set_exit_overload()(由test_helpers同一作者提供的PHPUnit).

  • 注意:此项目不再维护(自 2014 年起)。 (4认同)

pin*_*hic 7

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

die()您可以使用throw new RuntimeException()(或者您自己的异常类)而不是使用它,这也将暂停程序执行(尽管以不同的方式)并使用PHPUnit setExpectedException()来捕获它.如果您希望脚本die()在遇到该异常时,在用户级别打印绝对没有任何内容,请查看set_exception_handler().

具体来说,我正在考虑将set_exception_handler()-call放入测试不使用的引导程序文件的情况,因此无论情况如何,处理程序都不会触发,因此不会干扰PHPUnit的本机异常处理.

  • 当我的旧帖回答我的问题时,请喜欢它. (3认同)

Pet*_*all 5

这与我在获取一些遗留代码以通过测试时遇到的一系列问题有关。所以我想出了一个像这样的可测试类......

class Testable {
   static function exitphp() {
      if (defined('UNIT_TESTING')) {
         throw new TestingPhpExitException();
      } else {
         exit();
      }
   }
}
Run Code Online (Sandbox Code Playgroud)

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

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

  • 这在开始时可能看起来不错,但这只是为了测试而改变程序的行为,最终不会很好恕我直言 (8认同)