月度存档: 九月 2011

装饰WordPress

终于把空间里面几点遗留问题解决了,不是不报时候未到啊,曾经寻了千百度今天都轻松找到渠道。

1,Tag Cloud选用了wp-cumulus,解决了放大和Logo的问题,就势寻找到帖子完美的解决了中文Tag的问题。 http://www.lostleon.com/blog/2009/12/hacked-wp-cumulus-to-support-chinese/

2,代码高亮选择了Crayon,比较满意黑色底色的模版。

PHPUnit深入实践

近日在暴风成功推行了PHPUnit,这里记录一下实践的过程和心得。

安装

网上说的安装方法大致有两种,pear安装和自行下载压缩包安装,但是单独使用都不靠谱,两种结合一下就好了。

首先使用pear安装phpunit,具体操作步骤参考http://pear.phpunit.de/ 这是最便捷的取得最新版本并增加好所有依赖的方式。

然后取出runner文件夹中的PHPUnit.php,修改代码执行器目录到php的目录,并改名为PHPUnit,放在/usr/bin/文件夹下。(window用户可以设定path让它可以在环境中被找到)

基类整理

PHPUnit提供框架和数据库测试集成代码,但是封装了的工具并不完全够用,可以根据自己的需求增加一些更加实用的方法和类到基类中,如:

1,phpunit原生并不提供可以使用php数组进行数据库初始化的方式,所以需要一个额外的类去封装phpunit的Dataset方法,做到可以使用数组的方式组织初始数据,毕竟直接写在代码里的数组比额外的xml文件管理起来要方便的多,如:

Array DataSet
PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
/**
* 使用数组初始化数据库内容扩展类
* @author wangkepan
*
*/
class StromTest_DbUnit_ArrayDataSet extends PHPUnit_Extensions_Database_DataSet_AbstractDataSet
{
/**
* @var array
*/
protected $tables = array();
/**
* @param array $data
*/
public function __construct(array $data)
{
foreach ($data AS $tableName => $rows) {
$columns = array();
if (isset($rows[0])) {
$columns = array_keys($rows[0]);
}
$metaData = new PHPUnit_Extensions_Database_DataSet_DefaultTableMetaData($tableName, $columns);
$table = new PHPUnit_Extensions_Database_DataSet_DefaultTable($metaData);
foreach ($rows AS $row) {
$table->addRow($row);
}
$this->tables[$tableName] = $table;
}
}
protected function createIterator($reverse = FALSE)
{
return new PHPUnit_Extensions_Database_DataSet_DefaultTableIterator($this->tables, $reverse);
}
public function getTable($tableName)
{
if (!isset($this->tables[$tableName])) {
throw new InvalidArgumentException("$tableName is not a table in the current database.");
}
return $this->tables[$tableName];
}
}

2,对于一些protected 和 private 的方法,需要用反射类修改方法的可读性来对方法进行测试,实现方法参看http://stackoverflow.com/questions/249664/best-practices-to-test-protected-methods-with-phpunit

Reflection
PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
/**
* 取得私有对象方法。需要php版本大于5.3.2
* @param string $className
* @param string $methodName
* @return Ambiguous
*/
protected static function getMethod($className, $methodName)
{
$class = new ReflectionClass($className);
$method = $class->getMethod($methodName);
$method->setAccessible(true);
return $method;
}

3,对框架的初始化类,此处见仁见智,不一定要用类实现,只要达到目的。

框架整合

刚才提到对框架的整合,这里再补充一下对框架测试的心得。

选用框架ZF1.10,Zend的类库中已经对phpunit有了封装支持,这是非常方便的,不过对于版本上的兼容好像有一些问题,所以在DB的pdo初始化部分遇到了一些麻烦,由于Zend_Test_Phpunit_db并没有提供什么额外的功能,而且对于Model的测试DB_Unit已经足矣,故舍弃了集成Zend_Test的DB部分扩展,直接使用DB_Unit。这样做的唯一缺点是无法使用ZF的配置文件取得数据库参数,不过只要稍加修改手动引入各个变量就能达到目的。

框架测试部分择直接集成Zend封装之后的类,增加了对于Zend分发,路由,跳转,返回值路径等各方面页面等级的测试,相当强大,唯一的缺点是不具备数据库测试的功能,所以对于一些web接口类型的测试,显得有点力不从心。

终极整合:分析了一下类库源码,发现DB_Unit的主类和Zend的框架测试类继承的是同一父类,而且双方作为扩展都对通用性进行了处理,两方面也做的是完全不相干的事情,但是php不支持多继承,故用了一个下三滥的方法:拷贝出DB _Unit的主类,修改其父类为Zend框架测试类,自己封装的基类再继承拷贝出来的类,其代码不用做任何修改,则新的基类拥有了DB_Unit和Zend框架测试类的所有功能,可以同时对controller的分发和数据库反应进行测试,而且测试代码可以统一继承同一个基类,功能大大加强。

遗憾

必须拷贝出DB_Unit源码是非常不优雅的,而且可能会给后面的升级带来麻烦,但还未找到很合适的解决方法,也许反射可以做到这样的事情,研究了一下暂时未果。

另外一个比较难受的状态是无法(或未找到方法)对每个测试用例进行单独的数据初始化(虽然每个用例前都会做一次初始化),这就对新加入的测试造成一定的不便,因为需要去判断新加入的一些基础数据会不会对以前的测试造成影响。

第三点就是对controller的实例化比较麻烦(这个应该能解决,需要再深入研究一下zend框架),导致对Action的行为能够掌控,却无法对controller中的一些私有方法进行掌控,测试粒度比较大。

总结

总体来说当前的功能已经完全能够达到单元测试的目的了,虽然依旧存在一些问题,以后也一定会遇到更多问题,只要了解得足够详细,所有都会迎刃而解,钻研、想象力和追求完美的精神都不可缺少。

向往的地方

南美玻利维亚乌尤尼

除了北欧极光,想去的地方又多了一个。

下一步攒钱搞单反了,工作,旅游,创业。

极致

冯鑫说:得不到成功是因为成功的欲望还不够强烈。

冯鑫说:大多数选择问题,其实是排序问题。

冯鑫说:计划,总结,进步。

冯鑫说:事情做到极致,一定成功。

欲望,排序,进步,成功。

一部分关乎于人心的事情是不可套用的,只有顺其自然。

做任何事情加快10%是个值得实践的主意。

莫忘2014年10月的约定。

——这两天学到的和想起的,就用这个突然很有好感的词做标题吧。