本质上,我有一个名为 killProgram 的类的方法,它旨在发送一个 hTTP 重定向,然后杀死 PHP。
我应该如何测试这个?当我运行 phpunit 时,它不会为该测试返回任何内容,并完全关闭。
现在我正在考虑让 killProgram 函数抛出一个不应被处理的异常,这将允许我断言抛出了一个异常。
有没有更好的办法?
本质上,我有一个名为 killProgram 的类的方法,它旨在发送一个 hTTP 重定向,然后杀死 PHP。
我应该如何测试这个?当我运行 phpunit 时,它不会为该测试返回任何内容,并完全关闭。
现在我正在考虑让 killProgram 函数抛出一个不应被处理的异常,这将允许我断言抛出了一个异常。
有没有更好的办法?
这显然是一个老问题,但我的建议是将die()
's 的代码移动到一个单独的方法中,然后您可以模拟。
例如,而不是这样:
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();
}
}
我还没有测试过代码,但应该非常接近工作状态。
由于每个测试都由同一个 PHPUnit 进程运行,因此如果您在 PHP 代码中使用 exit/die,您将杀死一切——正如您所注意到的 ^^
所以,你必须找到另一个解决方案,是的——比如回归而不是死亡;或抛出异常(您可以测试某些测试代码是否抛出了预期的异常)。
也许 PHPUnit 3.4 和它的--process-isolation
开关(请参阅可选地使用单独的 PHP 进程执行每个测试)可能会有所帮助(不会让所有东西都死掉),但是如果 PHPUnit 没有得到,您仍然无法获得测试结果控制回来。
我遇到过几次这个问题;通过返回而不是死亡来解决它 - 如果需要,甚至返回几次,以便在调用堆栈中返回“足够高”^^
最后,我想我的应用程序中不再有任何“死亡”。 .. 在考虑 MVC 时,可能会更好,顺便说一句。
无需更改代码即可对其进行测试,您可以简单地使用set_exit_overload()
(由test_helpers
与 PHPUnit 相同的作者提供)。
我意识到你已经接受了这个答案,这是一个老问题,但我认为这可能对某人有用,所以这里是:
除了 using die()
,您还可以使用throw new RuntimeException()
(或您自己的异常类),这也将停止程序执行(尽管以不同的方式)并使用 PHPUnitsetExpectedException()
来捕获它。如果您希望您的脚本die()
在遇到该异常时,在用户级别上完全不打印任何内容,请查看set_exception_handler()
.
具体来说,我正在考虑一种场景,您将set_exception_handler()
-call 放入测试不使用的引导文件中,因此无论场景如何,处理程序都不会在那里触发,因此不会干扰 PHPUnit 的本机异常处理.
这与我一直在让一些遗留代码通过测试的一系列问题有关。所以我想出了一个像这样的可测试类......
class Testable {
static function exitphp() {
if (defined('UNIT_TESTING')) {
throw new TestingPhpExitException();
} else {
exit();
}
}
}
现在我只需用 Testable::exitphp() 替换对 exit() 的调用。
如果它在测试中,我只定义 UNIT_TESTING,在生产中我没有。看起来像一个简单的模拟。
您可以终止脚本或引发异常,具体取决于环境变量的值...
所以你在生产环境中杀死或在测试环境中抛出异常。
任何死亡或退出的调用,都会杀死整个过程......
这应该是一个评论,但我无法评论我的声誉点水平。