举例详解PHP脚本的测试方法 |
|
本文标签:PHP,测试 一、常用测试示例 我们经常会遇到这种情况:将一些没有经过任何测试的遗留代码进行重新编写测试,甚至这些代码还是用面向对象写的 。要对这样的代码进行测试,我的建议是把代码分解成块,这样就容易测试了 。 然而,这些遗留代码并不是那么好重构的,比如:测试前,你不能在把代码重新编写,这是为了避免影响原有程序,当然也不好进行单元测试 。 在PHP程序中,通常有一部分代码是写在几个index.php和script.php文件中的,这些.php文件存放在几个不同的文件夹里 。如果不找到它们的入口点,是无法直接由Web服务器访问的 。 测试副本 要测试一个PHP脚本,我们需要模拟一个HTTP请求,并检查返回的响应(response)是否等于预期值 。这里需要注意的是模拟一个请求,要定义response和request,这不仅仅是内容(content)的不同,而且他们的头信息(header)也是不同的 。 此外,如果我们想要测试一个操作数据的事务脚本,我们要确保不让它去连接真正的数据库或应用程序的其余部分 。 在现实中,通常没有人会直接拿原有的PHP脚本进行重写测试 。因为怕把代码弄得不可恢复 。我建议使用PHP脚本的副本,这样我们就可以将PHP代码进行一些小手术了 。 如何将代码进行最小修改:删除include和require语句(如果它们没有被用到),并且修改内部函数的调用方式,例如:将header()写成$object->header() 。 最后,我们来测试这个事务脚本 。测试完后,我们可以从副本脚本中提取出它们,并把它们放入新脚本文件中 。 具体步骤 一、模拟一个HTTP请求并重新定义变量$_GET和$_POST,还要修改$_SERVER的header 。 二、获取请求响应,response的body可以通过ob_start()和ob_get_clean()捕获,它可以收集每一个用echo()或以<?php标签输出的buffer(缓冲内容) 。 注意:输出缓冲支持在PHP多个级别的嵌套,所以在大多数情况下,都可以捕获到,即使脚本在使用ob_*调用本身 。 三、测试脚本应包含事务脚本的内部方法,因此在这个脚本范围内的方法都可以被调用 。例如: 具体代码 这就是我们要测试的事务脚本对象,具体到脚本中,我们还需要封装:
<?php
class ForumPosting
{
private $headers = array();
public function handleRequest($postRequest)
{
$_POST = $postRequest;
$connection = $this->getAConnection();
ob_start();
include forum/post_new_copy.php;
$content = ob_get_clean();
return array(
content => $content,
headers => $this->headers
);
}
private function header($headerLine)
{
$this->headers[] = $headerLine;
}
...
}
这是我们的测试代码:
public function testANewPostIsCreated()
{
$action = new ForumPosting();
$response = $action->handleRequest(array(
id_thread => 42,
text => Hello, world,
...
));
$this->assertEquals(..., $response[content]);
$this->assertContains(Content-type: text/html, $response[headers]);
}
测试副本只是暂时的!它让我们编写的测试不会改变 。最终,我们要将已经通过测试的PHP脚本进行重构,以消除冗余代码 。 当我们的测试完成后,可以将handleRequest()的内容替换成真正的逻辑代码 。假如你要写很多这样的测试脚本,你可以写一个通用的测试对象,以满足你的测试需要 。
在PHP领域,单元测试的工具主要有PHPUNIT,PHPUNIT2和SimpleTest三种 。其中PHPUNIT在功能上很简单,不算完善;PHPUNIT2是专门为PHP5写的单元测试工具,在结构和功能上都向Junit看齐;而SimpleTest则是一套非常实用的测试工具,其中的webTest支持对web程序界面的测试,是Easy最为推荐的一款测试工具 。在本文中,我们选择SimpleTest进行介绍 。 相关知识:PHPUNIT2也是一款很好的工具,尤其是架构上有很多值得圈点之处,希望将来能有机会在专门的文章中和大家分享 。 SimpleTest:就是这么Simple 安装SimpleTest很简单,上sf.net上下载一个源码包,然后解压到web目录下就可以使用了,这里就不多说 。 下面我们先来看个例子:编写一个测试,检查一个网站是否可以访问 。 首先我们引入要用到的文件: 代码列表:
require_once("../simpletest/unit_tester.php");
require_once("../simpletest/web_tester.php");
require_once("../simpletest/reporter.php");
然后我们创建一个测试类: 代码列表:
class TestOfSite extends WebTestCase
{
function TestOfSite()
{
$this->WebTestCase("测试");
}
function testSite()
{
$this->get("http://howgo.net/prettyface/display.php");
$this->assertTitle(".: facebook :.");
}
}
首先我们扩展了webTestCase类,这样我们就可以自动获得测试web的能力,然后在构造函数中我们直接使用基类的,只是把标题传给它 。接着我们就该写测试方法了,测试方法都是以‘test"开头的,用以识别在我们运行测试的时候,类中哪些方法要进行调用 。 而$this->get将取得网页的内容,我们指定它的标题为 ".: facebook :.", 接着我们要做的就是实例化这个类的对象,并运行它 。 代码列表: $test = &new TestOfSite(); $test->run(new HtmlReporter()); 下边是运行结果: 如果测试出错则会出现下边的界面: 到这里一个简单的测试就算完成了 。 实战演习 – 一个Login测试 下面我们进入实战,在这个基础上完成一个login的测试 。这次我们先贴出完整的代码: 代码列表:
require_once("../simpletest/unit_tester.php");
require_once("../simpletest/web_tester.php");
require_once("../simpletest/reporter.php");
class TestOfLogin extends WebTestCase
{
function TestOfLogin()
{
$this->WebTestCase("Login测试");
}
function testLoginOk()
{
// 取得页面
$this->get("http://howgo.net/prettyface/login.php");
// 添加测试表项
$this->setField("name","Easy");
$this->setField("pass","******");
// 提交
$this->clickSubmit("提交");
// 察看提交后返回页面是否正确
$this->assertWantedPattern("/成功登录/");
// 点击页面链接
$this->clickLink("点击这里进入管理页面");
// 察看指定页面标题和关键内容
$this->assertTitle("ADMINCP");
$this->assertWantedPattern("/请选择要进行的任务/");
// 退出登陆
$this->clickLink("退出管理");
$this->clickLink
}
}
|