我目前正在使用PHPUnit来尝试和我正在编写的内容一起开发测试,但是,我正在编写会话管理器,并且遇到了这样的问题......
Session处理类的构造函数是
private function __construct() { if (!headers_sent()) { session_start(); self::$session_id = session_id(); } }
但是,由于PHPUnit在开始测试之前发送文本,因此对此Object的任何测试都会返回失败的测试,因为HTTP"Headers"已经发送...
好吧,您的会话管理器基本上是按设计破解的.为了能够测试某些东西,必须能够将其与副作用隔离开来.不幸的是,PHP被设计以这样一种方式,它鼓励自由使用全局状态(echo
,header
,exit
,session_start
等等,等等).
您可以做的最好的事情是隔离组件中的副作用,这些副作用可以在运行时交换.这样,您的测试可以使用模拟对象,而实时代码使用具有真正副作用的适配器.你会发现这对单身人士来说效果不佳,我猜你正在使用它.因此,您必须使用其他一些机制来获取分配给代码的共享对象.您可以从静态注册表开始,但如果您不介意一点学习,还有更好的解决方案.
如果你不能这样做,你总是可以选择编写集成测试.例如.使用PHPUnit的等价物WebTestCase
.
为phpunit创建一个bootstrap文件,调用:
session_start();
然后像这样启动phpunit:
phpunit --bootstrap pathToBootstrap.php --anotherSwitch /your/test/path/
引导文件在其他所有内容之前被调用,因此标头尚未发送,一切都应该正常工作.
phpUnit在测试运行时输出输出,因此即使在第一次测试中,headers_sent()也会返回true.
要解决整个测试套件的这个问题,您只需在设置脚本中使用ob_start()即可.
例如,假设你有一个名为AllTests.php的文件,这是phpUnit加载的第一件事.该脚本可能如下所示:
addTest(YourFramework_AllTests::suite()); return $suite; } }
我有同样的问题,我通过使用--stderr标志调用phpunit来解决它,就像这样:
phpunit --stderr /path/to/your/test
希望它可以帮到某人!
我认为"正确"的解决方案是创建一个非常简单的类(这么简单,不需要测试),这是PHP的会话相关函数的包装,并使用它而不是session_start()
直接调用等.
在测试中传递模拟对象而不是真正有状态的,不可测试的会话类.
private function __construct(SessionWrapper $wrapper) { if (!$wrapper->headers_sent()) { $wrapper->session_start(); $this->session_id = $wrapper->session_id(); } }