我继承了一个Zend Framework Web应用程序,该应用程序既不面向对象也不在很多方面编写得很好,并且它没有进行任何测试。因此,虽然我很欣赏单元测试的价值,并且会在添加或重写代码时编写它们,但代码覆盖的功能测试似乎是最佳起点。它还是一个很好的学习工具,用于理解应用程序的工作原理。这是Zend Framework 1.11,Matthew Weier O'Phinney表示Zend_Test仅适用于PHPUnit到3.4。所以我安装了最新的3.4.15。我已经验证我可以扩展Zend_Test_PHPUnit_ControllerTestCase并在控制器上进行单元测试。
对于通过Selenium的功能测试,我在使代码覆盖工作时遇到了一些麻烦。事实上,我怀疑在Selenium服务器的工作方式下获取覆盖数据在技术上是可行的,但在Does PHPUnit_Selenium Code Coverage Work?和Does PHPUnit_Selenium Code Coverage Work?的帮助下,我终于使用了我的应用程序。很高兴能够看到代码的哪些部分被不同的请求所击中!
但我现在看到的问题是处理POST请求的代码似乎没有被报告。
例如在控制器中我有一个contactAction方法,其代码如下:
$this->view->form = $form;
if ($this->getRequest()->isPost()) {
if ($form->isValid($this->getRequest()->getPost())) {
$values = $form->getValues();
这是联系我们表格。在Selenium测试中,我打开网址,输入消息,单击提交按钮,然后等待页面加载。当我运行测试时,我可以在浏览器中看到这种情况,并接收带有由selenium输入的消息的电子邮件,因此我确定表单是使用有效数据发布的,并且后两行确实执行了。但在报道报告中,前两行是绿色,后两行是橙色。
我检测了prepend.php和append.php脚本以记录以下信息:
"(File: " . __FILE__ . "): REQUEST_METHOD: " . $_SERVER['REQUEST_METHOD'] . "\n" .
"REQUEST_URI: " . $_SERVER['REQUEST_URI'] . "\n" .
"_COOKIE['PHPUNIT_SELENIUM_TEST_ID']: '" . print_r(isset($_COOKIE['PHPUNIT_SELENIUM_TEST_ID']), 1) . "'\n" .
"_GET['PHPUNIT_SELENIUM_TEST_ID']: '" . print_r(isset($_GET['PHPUNIT_SELENIUM_TEST_ID']), 1) . "'\n" .
"_POST['PHPUNIT_SELENIUM_TEST_ID']: '" . print_r(isset($_POST['PHPUNIT_SELENIUM_TEST_ID']), 1) . "'\n" .
奇怪的是,只有前置脚本会被记录,而不是追加脚本。我不知道为什么,但它似乎不影响覆盖数据(至少对于GET请求)。我见过的唯一可能解释的是Zend MVC应用程序是否以exit()结尾?这有意义吗?
以下是联系我们互动记录的内容:
(File C:\xampp\htdocs\myapp\public\prepend.php): REQUEST_METHOD: GET
REQUEST_URI: /index/contact
_COOKIE['PHPUNIT_SELENIUM_TEST_ID']: '1'
_GET['PHPUNIT_SELENIUM_TEST_ID']: ''
_POST['PHPUNIT_SELENIUM_TEST_ID']: ''
extension_loaded('xdebug'): '1'
(File C:\xampp\htdocs\myapp\public\prepend.php): REQUEST_METHOD: GET
REQUEST_URI: /index/contact
_COOKIE['PHPUNIT_SELENIUM_TEST_ID']: '1'
_GET['PHPUNIT_SELENIUM_TEST_ID']: ''
_POST['PHPUNIT_SELENIUM_TEST_ID']: ''
extension_loaded('xdebug'): '1'
(File C:\xampp\htdocs\myapp\public\prepend.php): REQUEST_METHOD: POST
REQUEST_URI: /index/contact
_COOKIE['PHPUNIT_SELENIUM_TEST_ID']: '1'
_GET['PHPUNIT_SELENIUM_TEST_ID']: ''
_POST['PHPUNIT_SELENIUM_TEST_ID']: ''
extension_loaded('xdebug'): '1'
(File C:\xampp\htdocs\myapp\public\prepend.php): REQUEST_METHOD: GET
REQUEST_URI: /default/index/contact
_COOKIE['PHPUNIT_SELENIUM_TEST_ID']: '1'
_GET['PHPUNIT_SELENIUM_TEST_ID']: ''
_POST['PHPUNIT_SELENIUM_TEST_ID']: ''
extension_loaded('xdebug'): '1'
(File C:\xampp\htdocs\myapp\public\prepend.php): REQUEST_METHOD: GET
REQUEST_URI: /default/index/contact
_COOKIE['PHPUNIT_SELENIUM_TEST_ID']: '1'
_GET['PHPUNIT_SELENIUM_TEST_ID']: ''
_POST['PHPUNIT_SELENIUM_TEST_ID']: ''
extension_loaded('xdebug'): '1'
(File C:\xampp\htdocs\myapp\public\prepend.php): REQUEST_METHOD: GET
REQUEST_URI: /phpunit_coverage.php?PHPUNIT_SELENIUM_TEST_ID=a85030b0bcdb0460bfb17a83a373d6b5
_COOKIE['PHPUNIT_SELENIUM_TEST_ID']: ''
_GET['PHPUNIT_SELENIUM_TEST_ID']: '1'
_POST['PHPUNIT_SELENIUM_TEST_ID']: ''
extension_loaded('xdebug'): '1'
正如您所看到的,GET请求会被记录两次,而POST只会记录一次。也许这与以下事实有关:只有GET请求似乎被覆盖而POSTS却没有?但我真的不明白这种行为有多种方式,而且我不知道如何做才能帮助解决这个问题。
任何人都有任何想法,无论是为什么我没有获得POST请求的报道,或者下一步可能是什么来追踪它?
答案 0 :(得分:0)
在这个问题中,我推测可能如果Zend Framework调用exit(),这可能解释了为什么append.php脚本永远不会被记录。所以我在ZF库的整个源代码中搜索了对exit()的调用,发现只有三个:
library/Zend/Controller/Action/Helper/Redirector.php: exit();
library/Zend/Oauth/Consumer.php: exit(1);
library/Zend/OpenId.php: exit();
在这种情况下没有使用Oauth或OpenId。但是正如我在评论中指出的那样,POST请求代码在登录失败时显示覆盖,并且表单被重新显示,但是当它成功并且重定向到欢迎页面时发生了。所以重定向器看起来像是要检查的地方。
对于重定向,此应用程序的操作例程中的代码统一使用:
$this->_redirect("some-url");
我从未调查过它的工作原理或任何选项,因为它从来都不是问题。但是由于它可能导致覆盖问题,我阅读了它的文档并浏览了Zend源代码。我发现有一个简单的选项可以导致重定向不调用exit()。所以我把那些问题改成了:
return $this->_redirect("some-url", array('exit'=>false));
瞧,POST请求丢失的代码覆盖率出现了!
现在我想知道我是否应该覆盖_redirect,以便它总是抑制退出调用,或者我是否应该只在测试环境中执行此操作。我想在重定向上立即终止脚本可能会在生产中节省一些周期。
所以主要问题就解决了。但神秘之处仍然是我在append.php脚本中输入的日志代码仍然没有产生任何输出 - prepend.php脚本总是生成其日志输出,但从不append.php。没有来自append.php的输出使我在ZF中的exit()调用的轨迹上,但似乎还有其他原因导致输出没有产生。
我终于想出了这个。这只是附加脚本中的拼写错误。我无法相信它,因为我“知道”我添加到append.php的日志代码与prepend.php中的代码相同,已经从prepend到append进行了复制粘贴。但显然我在副本上发了一个胖子,错过了消息文本的最后一行。当我终于看到缺失的行时,我的第一反应是“那是不可能的,我应该得到一个语法错误,而不仅仅是缺少输出。”这是我预期的代码:
$msg ="\n(File " . __FILE__ . "): REQUEST_METHOD: " . $_SERVER['REQUEST_METHOD'] . "\n" .
"REQUEST_URI: " . $_SERVER['REQUEST_URI'] . "\n" .
"_COOKIE['PHPUNIT_SELENIUM_TEST_ID']: '" . print_r(isset($_COOKIE['PHPUNIT_SELENIUM_TEST_ID']), 1) . "'\n" .
"_GET['PHPUNIT_SELENIUM_TEST_ID']: '" . print_r(isset($_GET['PHPUNIT_SELENIUM_TEST_ID']), 1) . "'\n" .
"_POST['PHPUNIT_SELENIUM_TEST_ID']: '" . print_r(isset($_POST['PHPUNIT_SELENIUM_TEST_ID']), 1) . "'\n" .
"extension_loaded('xdebug'): '". print_r(extension_loaded('xdebug'), 1) . "'\n";
file_put_contents($GLOBALS['PHPUNIT_COVERAGE_DATA_DIRECTORY'] . "/msg.log", $msg, FILE_APPEND);
但我不小心错过了$ msg的最后一行。所以当我意识到它丢失了,并且在调用file_put_contents()之前看到了线上的悬空字符串连接运算符,起初我很困惑,我没有得到语法错误。但是当然php非常乐意使用$ msg的旧值(前置脚本中指定的值)调用file_put_contents(),并将其结果(写入的字节数)附加到分配给$ msg的字符串(然后从未使用过)!当你准确地看到代码时,没有什么实际上令人惊讶,但是如果假设你的正确代码的复制粘贴不可能出错,那么当你的思想蒙上阴影时,就会感到非常神秘!