仓酷云

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 866|回复: 19
打印 上一主题 下一主题

[学习教程] PHP编程:使用单位测试在每一个层上对PHP代码停止检...

[复制链接]
不帅 该用户已被删除
跳转到指定楼层
楼主
发表于 2015-2-4 00:01:05 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
然后大吼:别人可以,我为什么就不可以?(是不是有点阎罗教练的味道,默默的确是电影看多了,抽嘴巴是会痛的,各位其实明白这个道理了就行了)   测试驱动的开辟和单位测试是确保代码在经由修正和严重调剂以后仍然能如咱们希冀的一样任务的最新办法。在本文中,您将进修到若何在模块、数据库和用户界面(UI)层对本人的 PHP 代码停止单位测试。
如今是清晨 3 点。咱们如何才干晓得本人的代码仍然在任务呢?
Web 使用法式是 24x7 不中断运转的,因而我的法式是不是还在运转这个成绩会在早晨一向困扰我。单位测试已帮我对本人的代码创立了足够的信念 ―― 如许我就能够平稳地睡个好觉了。
单位测试 是一个为代码编写测试用例并主动运转这些测试的框架。测试驱动的开辟 是一种单位测试办法,其思惟是应当起首编写测试法式,并验证这些测试可以发明毛病,然后才入手下手编写需求经由过程这些测试的代码。当一切测试都经由过程时,咱们开辟的特征也就完成了。这些单位测试的价值是咱们可以随时运转它们 ―― 在签入代码之前,严重修正以后,或安排到正在运转的体系以后都可以。
PHP 单位测试
关于 PHP 来讲,单位测试框架是 PHPUnit2。可使用 PEAR 号令行作为一个 PEAR 模块来装置这个体系:% pear install PHPUnit2。
在装置这个框架以后,可以经由过程创立派生于 PHPUnit2_Framework_TestCase 的测试类来编写单位测试。
模块单位测试
我发明入手下手单位测试最好的中央是在使用法式的营业逻辑模块中。我利用了一个复杂的例子:这是一个对两个数字停止乞降的函数。为了入手下手测试,咱们起首编写测试用例,以下所示。
清单 1. TestAdd.php
<?php
require_once 'Add.php';
require_once 'PHPUnit2/Framework/TestCase.php';
class TestAdd extends PHPUnit2_Framework_TestCase
{
  function test1() { $this->assertTrue( add( 1, 2 ) == 3 ); }
  function test2() { $this->assertTrue( add( 1, 1 ) == 2 ); }
}
?>
这个 TestAdd 类有两个办法,都利用了 test 前缀。每一个办法都界说了一个测试,这个测试可以与清单 1 一样复杂,也能够非常庞杂。在本例中,咱们在第一个测试中只是复杂地判定 1 加 2 等于 3,在第二个测试中是 1 加 1 等于 2。
PHPUnit2 体系界说了 assertTrue() 办法,它用来测试参数中包括的前提值是不是为真。然后,咱们又编写了 Add.php 模块,最后让它发生毛病的了局。

清单 2. Add.php
<?php
function add( $a, $b ) { return 0; }
?>
如今运转单位测试时,这两个测试城市掉败。
清单 3. 测试掉败
% phpunit TestAdd.php
PHPUnit 2.2.1 by Sebastian Bergmann.
FF
Time: 0.0031270980834961
There were 2 failures:
1) test1(TestAdd)
2) test2(TestAdd)
FAILURES!!!
Tests run: 2, Failures: 2, Errors: 0, Incomplete Tests: 0.
如今我晓得这两个测试都可以正常任务了。因而,可以修正 add() 函数来真正地做实践的工作了。
<?php
function add( $a, $b ) { return $a+$b; }
?>

如今这两个测试都可以经由过程了。
清单 4. 测试经由过程
% phpunit TestAdd.php
PHPUnit 2.2.1 by Sebastian Bergmann.
..
Time: 0.0023679733276367
OK (2 tests)
%
虽然这个测试驱动开辟的例子十分复杂,然而咱们可以从中体味到它的思惟。咱们起首创立了测试用例,而且有足够多的代码让这个测试运转起来,不外了局是毛病的。然后咱们验证测试切实其实是掉败的,接实在现了实践的代码使这个测试可以经由过程。
我发明在完成代码时我会一向不休地添加代码,直到具有一个掩盖一切代码途径的完全测试为止。在本文的最初,您会看到有关编写甚么测试和若何编写这些测试的一些建议。
数据库测试
在停止模块测试以后,就能够停止数据库会见测试了。数据库会见测试 带来了两个风趣的成绩。起首,咱们必需在每次测试之前将数据库恢复到某个已知点。其次,要注重这类恢复能够会对现无数据库形成损坏,因而咱们必需对非临盆数据库停止测试,或在编写测试用例时注重不克不及影响现无数据库的内容。
数据库的单位测试是从数据库入手下手的。为了论述这个成绩,咱们需求利用上面的复杂形式。
清单 5. Schema.sql
DROP TABLE IF EXISTS authors;
CREATE TABLE authors (
  id MEDIUMINT NOT NULL AUTO_INCREMENT,
  name TEXT NOT NULL,
  PRIMARY KEY ( id )
);

清单 5 是一个 authors 表,每笔记录都有一个相干的 ID。
接上去,就能够编写测试用例了。
清单 6. TestAuthors.php
<?php
require_once 'dblib.php';
require_once 'PHPUnit2/Framework/TestCase.php';
class TestAuthors extends PHPUnit2_Framework_TestCase
{
  function test_delete_all() {
     $this->assertTrue( Authors::delete_all() );
  }
  function test_insert() {
     $this->assertTrue( Authors::delete_all() );
     $this->assertTrue( Authors::insert( 'Jack' ) );
  }
  function test_insert_and_get() {
     $this->assertTrue( Authors::delete_all() );
     $this->assertTrue( Authors::insert( 'Jack' ) );
     $this->assertTrue( Authors::insert( 'Joe' ) );
     $found = Authors::get_all();
     $this->assertTrue( $found != null );
     $this->assertTrue( count( $found ) == 2 );
  }
}
?>
这组测试掩盖了从表中删除作者、向表中拔出作者和在验证作者是不是存在的同时拔出作者等功效。这是一个累加的测试,我发明关于寻觅毛病来讲这十分有效。察看一下哪些测试可以正常任务,而哪些测试不克不及正常任务,就能够疾速地找出哪些中央失足了,然后就能够进一步了解它们之间的区分。
最后发生掉败的 dblib.php PHP 数据库会见代码版本以下所示。
清单 7. dblib.php
<?php
require_once('DB.php');
class Authors
{
  public static function get_db()
  {
    $dsn = 'mysql://root:password@localhost/unitdb';
    $db =& DB::Connect( $dsn, array() );
    if (PEAR::isError($db)) { die($db->getMessage()); }
    return $db;
  }
  public static function delete_all()
  {
    return false;
  }
  public static function insert( $name )
  {
    return false;
  }
  public static function get_all()
  {
    return null;
  }
}
?>

对清单 8 中的代码履行单位测试会显示这 3 个测试全体掉败了:
清单 8. dblib.php
% phpunit TestAuthors.php
PHPUnit 2.2.1 by Sebastian Bergmann.
FFF
Time: 0.007500171661377
There were 3 failures:
1) test_delete_all(TestAuthors)
2) test_insert(TestAuthors)
3) test_insert_and_get(TestAuthors)
FAILURES!!!
Tests run: 3, Failures: 3, Errors: 0, Incomplete Tests: 0.
%
如今咱们可以入手下手添加准确会见数据库的代码 ―― 一个办法一个办法地添加 ―― 直到一切这 3 个测试都可以经由过程。终究版本的 dblib.php 代码以下所示。
清单 9. 完全的 dblib.php
<?php
require_once('DB.php');
class Authors
{
  public static function get_db()
  {
    $dsn = 'mysql://root:password@localhost/unitdb';
    $db =& DB::Connect( $dsn, array() );
    if (PEAR::isError($db)) { die($db->getMessage()); }
    return $db;
  }
  public static function delete_all()
  {
    $db = Authors::get_db();
    $sth = $db->prepare( 'DELETE FROM authors' );
    $db->execute( $sth );
    return true;
  }
  public static function insert( $name )
  {
    $db = Authors::get_db();
    $sth = $db->prepare( 'INSERT INTO authors VALUES (null,?)' );
    $db->execute( $sth, array( $name ) );
    return true;
  }
  public static function get_all()
  {
    $db = Authors::get_db();
    $res = $db->query( "SELECT * FROM authors" );
    $rows = array();
    while( $res->fetchInto( $row ) ) { $rows []= $row; }
    return $rows;
  }
}
?>

在对这段代码运转测试时,一切的测试都可以没有成绩地运转,如许咱们就能够晓得本人的代码可以准确任务了。
HTML 测试
对全部 PHP 使用法式停止测试的下一个步调是对前真个超文本标志言语(HTML)界面停止测试。要停止这类测试,咱们需求一个以下所示的 Web 页面。

这个页面临两个数字停止乞降。为了对这个页面停止测试,咱们起首从单位测试代码入手下手动手。
清单 10. TestPage.php
<?php
require_once 'HTTP/Client.php';
require_once 'PHPUnit2/Framework/TestCase.php';
class TestPage extends PHPUnit2_Framework_TestCase
{
  function get_page( $url )
  {
    $client = new HTTP_Client();
    $client->get( $url );
    $resp = $client->currentResponse();
    return $resp['body'];
  }
  function test_get()
  {
    $page = TestPage::get_page( 'http://localhost/unit/add.php' );
    $this->assertTrue( strlen( $page ) > 0 );
    $this->assertTrue( preg_match( '/<html>/', $page ) == 1 );
  }
  function test_add()
  {
    $page = TestPage::get_page( 'http://localhost/unit/add.php?a=10&b=20' );
    $this->assertTrue( strlen( $page ) > 0 );
    $this->assertTrue( preg_match( '/<html>/', $page ) == 1 );
    preg_match( '/<span id="result">(.*?)<\/span>/', $page, $out );
    $this->assertTrue( $out[1]=='30' );
  }
}
?>

这个测试利用了 PEAR 供应的 HTTP Client 模块。我发明它比内嵌的 PHP Client URL Library(CURL)更复杂一点儿,不外也能够利用后者。
有一个测试会反省所前往的页面,并判别这个页面是不是包括 HTML。第二个测试会经由过程将值放到恳求的 URL 中来恳求盘算 10 和 20 的和,然后反省前往的页面中的了局。
这个页面的代码以下所示。

清单 11. TestPage.php
<html><body><form>
<input type="text" name="a" value="<?php echo($_REQUEST['a']); ?>" /> +
<input type="text" name="b" value="<?php echo($_REQUEST['b']); ?>" /> =
<span id="result"><?php echo($_REQUEST['a']+$_REQUEST['b']); ?></span>
<br/>
<input type="submit" value="Add" />
</form></body></html>

这个页面相当复杂。两个输出域显示了恳求中供应确当前值。了局 span 显示了这两个值的和。<span> 标志标出了一切区分:它关于用户来讲是不成见的,然而关于单位测试来讲倒是可见的。因而单位测试其实不需求庞杂的逻辑来找到这个值。相反,它会检索一个特定 <span> 标志的值。如许当界面产生变更时,只需 span 存在,测试就能够经由过程。
与后面一样,起首编写测试用例,然后创立一个掉败版本的页面。咱们对掉败情形停止测试,然后修正页面的内容使其可以任务。了局以下:

清单 12. 测试掉败情形,然后修正页面
% phpunit TestPage.php
PHPUnit 2.2.1 by Sebastian Bergmann.
..
Time: 0.25711488723755
OK (2 tests)
%

这两个测试都可以经由过程,这就意味着测试代码可以正常任务。
不外对 HTML 前真个测试有一个缺点:JavaScript。超文本传输协定(HTTP)客户机代码对页面停止检索,然而却没有履行 JavaScript。因而假如咱们在 JavaScript 中有良多代码,就必需创立用户代办署理级的单位测试。我发明完成这类功效的最好办法是利用 Microsoft
若天明 该用户已被删除
沙发
发表于 2015-2-4 08:02:31 | 只看该作者
真正的方向了,如果将来要去开发团队,你一定要学好smarty ,phplib这样的模板引擎,
柔情似水 该用户已被删除
板凳
发表于 2015-2-9 19:38:46 | 只看该作者
写js我最烦的就是 ie 和 firefox下同样的代码 结果显示的结果千差万别,还是就是最好不要用遨游去调试,因为有时候遨游是禁用js的,有可能代码是争取结果被遨游折腾的认为是代码写错。
爱飞 该用户已被删除
地板
发表于 2015-2-10 10:53:45 | 只看该作者
爱上php,他也会爱上你。
活着的死人 该用户已被删除
5#
发表于 2015-2-11 04:07:04 | 只看该作者
首先声明:我是一个菜鸟,是一个初学者。学习了一段php后总是感觉自己没有提高,无奈。经过反思我认为我学习过程中存在很多问题,我改变了学习方法后自我感觉有了明显的进步。
冷月葬花魂 该用户已被删除
6#
发表于 2015-2-16 20:14:32 | 只看该作者
爱上php,他也会爱上你。
山那边是海 该用户已被删除
7#
发表于 2015-2-20 13:47:55 | 只看该作者
我还是强烈建议自己搭建php环境。因为在搭建的过程中你会遇到一些问题,通过搜索或是看php手册解决问题后,你会更加深刻的理解它们的工作原理,了解到php配置文件中的一些选项设置。
若相依 该用户已被删除
8#
发表于 2015-3-10 19:15:47 | 只看该作者
实践是检验自己会不会的真理。
再现理想 该用户已被删除
9#
发表于 2015-3-17 09:10:34 | 只看该作者
个人呢觉得,配wamp 最容易漏的一步就是忘了把$PHP$目录下的libmysql.dll拷贝到windows系统目录的system32目录下,还有重启apache。
海妖 该用户已被删除
10#
发表于 2015-3-24 05:19:15 | 只看该作者
装在C盘下面可以利用windows的ghost功能可以还原回来(顺便当做是重转啦),当然啦我的编译目录要放在别的盘下,不然自己的劳动成果就悲剧啦。
第二个灵魂 该用户已被删除
11#
发表于 2015-3-27 07:10:20 | 只看该作者
写的比较杂,因为我也是个新手,不当至于大家多多指正。
admin 该用户已被删除
12#
发表于 2015-4-3 22:39:12 | 只看该作者
首先我是坚决反对新手上来就用框架的,因为对底层的东西一点都不了解,造成知识上的真空,会对以后的发展不利。我的观点上手了解下框架就好,代码还是手写。当然啦如果是位别的编程语言的高手的话,这个就另当别论啦。
13#
发表于 2015-4-3 23:28:05 | 只看该作者
建议加几个专业的phper的群,当然啦需要说话的人多,一处一点问题能有人回答你的,当然啦要让人回答你的问题,平时就得躲在里面聊天,大家混熟啦,愿意回答你问题的人自然就多啦。
谁可相欹 该用户已被删除
14#
发表于 2015-4-15 01:39:20 | 只看该作者
如果你可以写完像留言板这样的程序,那么你可以去一些别人的代码了,
金色的骷髅 该用户已被删除
15#
发表于 2015-4-16 07:52:01 | 只看该作者
首推的搜索引擎当然是Google大神,其次我比较喜欢 百度知道。不过搜出来的结果往往都是 大家copy来copy去的,运气的的概率很大。
因胸联盟 该用户已被删除
16#
发表于 2015-4-30 18:14:02 | 只看该作者
最后介绍一个代码出错,但是老找不到错误方法,就是 go to wc (囧),出去换换气没准回来就找到错误啦。
精灵巫婆 该用户已被删除
17#
发表于 2015-5-1 11:36:58 | 只看该作者
你很难利用原理去编写自己的代码。对于php来说,系统的学习我认为还是很重要的,当你有一定理解后,你可你针对某种效果研究,我想那时你不会只是复制代码的水平了。
小女巫 该用户已被删除
18#
发表于 2015-5-6 20:10:34 | 只看该作者
建数据库表的时候,int型要输入长度的,其实是个摆设的输入几位都没影响的,只要大于4就行,囧。
简单生活 该用户已被删除
19#
发表于 2015-6-14 14:48:00 | 只看该作者
学习php的目的往往是为了开发动态网站,phper就业的要求也涵盖了很多。我大致总结为:精通php和mysql
再见西城 该用户已被删除
20#
发表于 2015-6-18 05:04:00 | 只看该作者
为了以后维护的方便最好是代码上都加上注释,“予人方便,自己方便”。此外开发文档什么的最好都弄齐全。我觉得这是程序员必备的素质。虽然会消耗点很多的时间。但是确实是非常有必要的。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|仓酷云 鄂ICP备14007578号-2

GMT+8, 2024-11-14 13:53

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表