PHPUnit – unit testing,需要发送标题的项目

我目前正在与PHPUnit一起尝试开发与我正在编写的testing,但是,我目前正在编写会话pipe理器,并遇到问题这样做…

Session处理类的构造函数是

private function __construct() { if (!headers_sent()) { session_start(); self::$session_id = session_id(); } } 

但是,由于PHPUnit在开始testing之前发送文本,所以对此对象的任何testing都会返回一个失败的testing,因为已经发送了HTTP“Headers”…

那么,你的会话pipe理器基本上被devise破坏了。 为了能够testing某些东西,必须将其与副作用隔离开来。 不幸的是,PHP是这样devise的,它鼓励自由使用全局状态( echoheaderexitsession_start等)。

你可以做的最好的事情是隔离组件中的副作用,可以在运行时交换。 这样,您的testing可以使用模拟对象,而实时代码则使用适配器,它具有真正的副作用。 你会发现,这与单身人士,我猜你正在使用的不好。 所以你必须使用一些其他机制来获得分配给你的代码的共享对象。 你可以从一个静态的registry开始,但是如果你不介意学习一些东西,那还有更好的解决办法。

如果你不能这样做,你总是可以select编写集成testing。 例如。 使用PHPUnit的等价的WebTestCase

phpUnit在testing运行时打印输出,因此即使在第一次testing中也会导致headers_sent()返回true。

要解决整个testing套件中的这个问题,只需在设置脚本中使用ob_start()即可。

例如,假设您有一个名为AllTests.php的文件,这是phpUnit加载的第一个文件。 该脚本可能如下所示:

 <?php ob_start(); require_once 'YourFramework/AllTests.php'; class AllTests { public static function suite() { $suite = new PHPUnit_Framework_TestSuite('YourFramework'); $suite->addTest(YourFramework_AllTests::suite()); return $suite; } } 

为phpunit创build一个引导文件,调用:

 session_start(); 

然后像这样开始phpunit:

 phpunit --bootstrap pathToBootstrap.php --anotherSwitch /your/test/path/ 

引导文件在一切之前被调用,所以头没有被发送,一切都应该正常工作。

我有同样的问题,我解决了这个问题,通过调用phpunit –stderr标志就像这样:

 phpunit --stderr /path/to/your/test 

希望它可以帮助别人!

我认为“正确的”解决scheme是创build一个非常简单的类(非常简单,不需要testing),它是PHP会话相关函数的一个包装,而不是直接调用session_start()等。

在testing中传递模拟对象而不是真正的有状态,不可testing的会话类。

 private function __construct(SessionWrapper $wrapper) { if (!$wrapper->headers_sent()) { $wrapper->session_start(); $this->session_id = $wrapper->session_id(); } } 

在开始testing之前不能使用输出缓冲吗? 如果你缓冲了输出的所有内容,那么在设置任何头文件时都不会有问题,因为在这一点上还没有输出到客户端。

即使在课堂上使用OB,它也是可堆叠的,OB不应该影响里面的内容。

据我所知Zend框架使用相同的输出缓冲他们的Zend_Session包testing。 你可以看看他们的testing案例,让你开始。

引导文件的创build,指出了4个post回来似乎是最清洁的方式。

通常在PHP中,我们不得不维护,并且尝试为遗留下来的遗留项目添加某种工程学科。 我们没有时间(或者权威)把整堆垃圾抛弃,重新开始,所以第一个stream氓软件并不总是可行的。 (如果我们可以回到最初的devise,那么我们可以完全抛弃PHP,并使用更现代的东西,比如ruby或python,而不是帮助维持Web开发世界的COBOL。)

如果您正在尝试为使用session_start或setcookie的模块编写unit testing,那么比在boostrap文件中启动会话可以更好地解决这些问题。

因为我现在unit testing我的bootstrap(是的,我知道你们大多数人不这样做),我遇到了同样的问题(header()和session_start())。 我find的解决scheme非常简单,在你的unittest引导程序中定义一个常量,并简单地在发送头文件或开始会话之前检查它:

 // phpunit_bootstrap.php define('UNITTEST_RUNNING', true); // bootstrap.php (application bootstrap) defined('UNITTEST_RUNNING') || define('UNITTEST_RUNNING', false); ..... if(UNITTEST_RUNNING===false){ session_start(); } 

我同意这不是完美的devise,但我unit testing现有的应用程序,重写大部分是不希望的。 我也使用相同的逻辑来使用__call()和__set()魔术方法来testing私有方法。

 public function __set($name, $value){ if(UNITTEST_RUNNING===true){ $name='_' . $name; $this->$name=$value; } throw new Exception('__set() can only be used when unittesting!'); } 

我想知道为什么没有人列出XDebug选项:

 /** * @runInSeparateProcess * @requires extension xdebug */ public function testGivenHeaderIsIncludedIntoResponse() { $customHeaderName = 'foo'; $customHeaderValue = 'bar'; // Here execute the code which is supposed to set headers // ... $expectedHeader = $customHeaderName . ': ' . $customHeaderValue; $headers = xdebug_get_headers(); $this->assertContains($expectedHeader, $headers); } 

看来你需要注入会话,以便你可以testing你的代码。 我使用的最佳选项是Aura.Auth用于身份validation过程,并使用NullSession和NullSegment进行testing。

灵气testing空会议

Aura框架写得很漂亮,你可以自己使用Aura.Auth,而不需要其他的Aura框架依赖。