如果该函数应该杀死 PHP,您如何使用 PHPUnit 来测试该函数?
Posted
技术标签:
【中文标题】如果该函数应该杀死 PHP,您如何使用 PHPUnit 来测试该函数?【英文标题】:How do you use PHPUnit to test a function if that function is supposed to kill PHP? 【发布时间】:2010-11-23 18:49:17 【问题描述】:基本上我有一个名为 killProgram 的类的方法,它旨在发送一个 hTTP 重定向,然后杀死 php。
我应该如何测试这个?当我运行 phpunit 时,它不会为该测试返回任何内容,并完全关闭。
现在我正在考虑让 killProgram 函数抛出一个不应被处理的异常,这样我就可以断言抛出了一个异常。
有没有更好的办法?
【问题讨论】:
理论上,register_shutdown_function 或许能够提供解决方案,尽管我不太确定这样做的含义。 【参考方案1】:由于每个测试都由同一个 PHPUnit 进程运行,如果您在 PHP 代码中使用 exit/die,您将杀死一切——正如您所注意到的那样 ^^
所以,你必须找到另一个解决方案,是的——比如返回而不是死亡;或者抛出异常(你可以测试一些被测试的代码是否抛出了预期的异常)。
也许是 PHPUnit 3.4 和它的 --process-isolation
开关(参见 Optionally execute each test using a separate PHP process)可能帮助 (不会让所有东西都死掉),但你仍然无法获取测试结果,如果 PHPUnit 没有取回控制权。
我遇到过几次这个问题;通过返回而不是死亡来解决它——如果需要,甚至返回几次,以便在调用堆栈中返回“足够高”^^ 最后,我想我的应用程序中不再有任何“死亡”了......在考虑 MVC 时,这可能会更好,顺便说一句。
【讨论】:
是的,现在我决定抛出一个异常。问题是我的默认异常处理程序旨在调用此函数,因此我必须创建一个名为 killProgramException 的新异常,我的异常处理程序会忽略该异常。有点老套【参考方案2】:我知道你已经接受了这个问题的答案,这是一个老问题,但我认为这可能对某人有用,所以这里是:
您可以使用throw new RuntimeException()
(或您自己的异常类)代替die()
,这也会停止程序执行(尽管以不同的方式)并使用PHPUnit 的setExpectedException()
来捕获它。如果您希望您的脚本在遇到该异常时使用die()
,在用户级别上完全不打印任何内容,请查看set_exception_handler()
。
具体来说,我正在考虑一个场景,您将 set_exception_handler()
-call 放入测试不使用的引导文件中,因此无论场景如何,处理程序都不会在那里触发,所以什么都没有干扰 PHPUnit 的原生异常处理。
【讨论】:
喜欢我的旧帖子回答了我的问题。 这个答案基本上建议使用异常作为流控制结构,这通常是不可取的。【参考方案3】:无需更改代码即可进行测试,您只需使用set_exit_overload()
(由与PHPUnit 相同作者的test_helpers
提供)。
【讨论】:
懒人的链接:github.com/php-test-helpers/php-test-helpers(注意这是一个 PHP 扩展,需要在 php.ini 中激活) 注意:此项目不再维护(自 2014 年起)。【参考方案4】:这与我在获取一些遗留代码以通过测试时遇到的一系列问题有关。所以我想出了一个像这样的可测试类......
class Testable
static function exitphp()
if (defined('UNIT_TESTING'))
throw new TestingPhpExitException();
else
exit();
现在我只需用 Testable::exitphp() 替换对 exit() 的调用。
如果它在测试中,我只定义 UNIT_TESTING,在生产中我没有。看起来像一个简单的 Mock。
【讨论】:
IMO,这非常优雅。谢谢。 这在开始时可能看起来不错,但这只是为了测试而改变程序的行为,这最终不会很好恕我直言【参考方案5】:这显然是一个老问题,但我的建议是将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();
我还没有测试过代码,但应该非常接近工作状态。
【讨论】:
【参考方案6】:您可以终止脚本或抛出异常,具体取决于环境变量的值...
所以你在生产环境中杀死或在测试环境中抛出异常。
任何死亡或退出的调用,都会杀死整个过程......
这应该是评论,但我无法评论我的声誉点数。
【讨论】:
以上是关于如果该函数应该杀死 PHP,您如何使用 PHPUnit 来测试该函数?的主要内容,如果未能解决你的问题,请参考以下文章