Ignore exit() and die() with PHPUnit


Ignore exit() and die() with PHPUnit

首先,标题会暗示这是这个或这个的副本,但出于几个原因,这些答案对我不起作用,即使我最初的问题是相同的。我来解释为什么。

我的问题是:我有几个场合在我的代码中,我想发送一个头和一个体,然后终止处理。与其他问题不同,我不能使用return或抛出异常(这些显然是为不同目的而设计的不同函数,而不是exit,这不是错误;它只是在某些特定情况下提前终止运行时)。

仍然,我想编写运行这些方法的单元测试,确保设置了适当的头(解决方案在这里找到),输出体是正确的(在测试用例中使用$this->expectOutputString() -方法解决),然后继续测试。在两者之间,exit会发生。

我已经在PHPUnit中尝试了@runInSeparateProcess -注释,我也检查了test_helpers扩展,它可以工作,但我不想添加另一个扩展(请注意测试也将在生产中运行),因为一行本地PHP代码会破坏一切。一定有一种不牺牲最佳实践的更简单的方法。

谁有解决这个问题的好办法?

我在bootstrap中添加了一个变量,在我不需要退出的极少数情况下,我可以在代码中使用IF引用它。

define ('PHPUNIT_RUNNING', 1); 

正常程序:

if(! @PHPUNIT_RUNNING === 1 )
{
    exit;
}

PHPUnit没有被定义为规则,所以在PHP执行中会产生一个警告(我们用@隐藏它)。代码将在非测试模式下做我们想做的事情。这是在编写主代码之后添加的,因为我们将PHPUnit测试添加到现有项目中,而不是进行TDD。

请注意:

为了解决遗留问题,我们尽可能少地这样做,否则我们会按照其他人的建议抛出异常或将数据返回给父函数。

我刚刚测试了以下想法:

ExitException.php:

<?php
class DieException extends Exception {} // for those people who like die as well as exit
class ExitException extends Exception {}

entrypoint.php:

<?php
require_once 'ExitException.php';
try {
  require 'main_code.php';
  run_main_code();
}
catch (DieException $e) {
  return $e->getMessage();
}
catch (ExitException $e) {
  return $e->getMessage();
}

几个include s后:

deepcode.php

<?php
throw new ExitException('Exiting normally');

这模拟了在最顶层捕获的exitdie。您的程序将像以前一样退出,现在它是可测试的,而不会杀死整个测试套件。唯一的问题是,如果你在现有的代码中也捕获了其他普通的Exception,在这种情况下,你将不得不修改你的代码来重新抛出DieException/ExitException,直到它们达到顶级。

另一种选择是干净地返回,这可能涉及重写大量代码。也就是说,如果你没有在那个点退出,为什么你的程序会产生更多的输出?它应该尽可能早地检查是否需要"提前退出",然后只调用该代码并一直流到程序的自然结束。

如果你必须处理第三方库或其他你不应该或不能改变的代码,这个问题就会变得更加困难,但是除非它们有自己的单元测试,否则为它们编写测试是没有价值的,因为理想情况下,你不应该改变第三方代码来避免未来的兼容性问题。一个编写良好的第三方库不应该die。它应该总是将控制返回给调用程序,或者抛出一个可以被捕获的Exception