在Mac OS上搭建PHP的Yii框架及相关测试环境
《在Mac OS上搭建PHP的Yii框架及相关测试环境》要点: YII集成了单元测试和功能测试,借助phpunit和selenium实现.笔者在配置过程中遇到了不少麻烦,纪录在此.PHP应用 必要概念 phpunit YII框架如何集成 环境安装 JDK selenium-server $ brew install selenium-server-standalone 由于selenium-server的源在googleapis上,所以需要翻墙才能进行操作,事实上,如果不翻墙,其他步骤也比拟困难. 安装完成后的提示: To have launchd start selenium-server-standalone at login: ln -sfv /usr/local/opt/selenium-server-standalone/*.plist ~/Library/LaunchAgents Then to load selenium-server-standalone now: launchctl load ~/Library/LaunchAgents/homebrew.mxcl.selenium-server-standalone.plist Or,if you don't want/need launchctl,you can just run: selenium-server -p 4444 这里明确告诉我们通过如下命令来启动服务端 $ selenium-server -p 4444 正如所见,通常selenium-server侦听4444端口,如果希望修改端口,那么相应的Yii处必要修改一下配置. phpunit phar是一种php打包方案.也就是可以把一个php程序或者php网站打包在一起分发,甚至被作为一个功能模块调用.因此,phpunit完全可以将工具程序打包成phar,执行phar的时候,通常必要使用php命令. $ wget https://phar.phpunit.de/phpunit.phar $ chmod +x phpunit.phar $ sudo mv phpunit.phar /usr/local/bin/phpunit $ phpunit --version PHPUnit x.y.z by Sebastian Bergmann and contributors. 用上面的命令可以下载phpunit的可执行文件,可以看到这是个phar包 pear是php扩展库的体系,因为早期php复用比较困难.编译型语言由于语法比较紧凑和严谨,比较容易复用.而php由于灵活多变,复用起来学习本钱比较高,于是pear就提出了一个编程规范和分发体系来实现php的功能复用,现在似乎pear已经被composer替代了(下面会说).不过古老的东西既然已经走过弯路了不妨记下来. 在mac下可以这么安装pear: $ wget http://pear.php.net/go-pear.phar $ sudo php -d detect_unicode=0 go-pear.phar 可以看到,go-pear也是个phar,只不过它是一个安装pear的php脚本,使用php命令可以执行.安装过程中会提示是否要修改php.ini文件: WARNING! The include_path defined in the currently used php.ini does not contain the PEAR PHP directory you just specified: </usr/share/pear> If the specified directory is also not in the include_path used by your scripts,you will have problems getting any PEAR packages working. Would you like to alter php.ini </etc/php.ini>? [Y/n] : Y php.ini </etc/php.ini> include_path updated. Current include path : .: Configured directory : /usr/share/pear Currently used php.ini (guess) : /etc/php.ini Press Enter to continue: The 'pear' command is now at your service at /usr/bin/pear ** The 'pear' command is not currently in your PATH,so you need to ** use '/usr/bin/pear' until you have added ** '/usr/bin' to your PATH environment variable. 从这段提示我们可以得知: pear的可执行程序安装在/usr/bin/pear ;***** Added by go-pear include_path=".:/usr/share/pear" ;***** 当我们在php使用require等包括其他文件的函数时,php其实除了搜索当前目录,还会搜索include_path.这样配置就表明,通过pear安装的程序代码将存放在工作目录,而且php能够找到,默认在工作目录下会有一个System.php,所以以下代码是可以工作的: <?php require 'System.php'; ?>
首先安装composer,在翻墙状态下: $ brew update $ brew tap josegonzalez/homebrew-php $ brew tap homebrew/versions $ brew install php55-intl $ brew install josegonzalez/php/composer 这样composer就装好了. 在项目的根目录下,创建一个composer.json,写入: { "require-dev": { "phpunit/phpunit": "4.7.*","phpunit/php-invoker": "*","phpunit/dbunit": ">=1.2","phpunit/phpunit-selenium": ">=1.2","phpunit/phpunit-story": "*" } } 上面的phpunit-selenium就是基于phpunit写的selenium客户端库,详见文后的参考资料. 然后在项目根目录下,执行 $ sudo composer install composer会根据这个composer.json文件在根目录创建一个vendor目录,并将依赖的东西全部下载到这个目录中,其中vendor/bin下面有phpunit的可执行文件. 由于是Yii的项目,所以cd到/protected/tests目录下,执行如下命令即可启动默认的SiteTest.php里面的测试办法: (注意在执行前,保持selenium-server开启状态) $ ../../vendor/bin/phpunit functional/SiteTest.php 会看到firefox会在执行过程中自动启动,并由如下日志输出: PHPUnit 4.7.7 by Sebastian Bergmann and contributors. Warning: Deprecated configuration setting "selenium" used . Time: 11.52 seconds,Memory: 6.50Mb OK (1 test,1 assertion) phpunit工具程序会自动找到tests/phpunit.xml这个配置文件并根据此来进行某些配置,而Yii会利用phpunit和phpunit-selenium的框架来与selenium-server端通信,server端会启动浏览器,并将日志和结果等返回给客户端.整个过程大致就是这样的. 测试 测试是软件开发中必不可少的环节.无论我们是否意识到,在开发Web应用的时候,我们始终都是在测试的.例如,当我们用PHP写了一个类时,我们可能会用到一些注入 echo 或者 die 语句来显示我们是否正确地实现了某个方法;当我们实现了包含一套复杂的HTML表单的web页面时,我们可能会试着输入一些测试数据来确认页面是否是依照我们的预期来交互的.更高级的开发者则会写一些代码来自动完成这个测试过程,这样一来每当我们需要测试一些东西的时候,我们只需要调用代码,剩下来的就交给计算机了. 这就是所谓的 自动测试,也是本章的主要话题. Yii 提供的测试支持包含 单元测试 和 功能测试. 单元测试检验了代码的一个独立单元是否依照预期工作. 在面向对象编程中,最基本的代码单元就是类. 因此,单元测试的主要职责就是校验这个类所实现的每个方法工作都是正常的. 单元测试通常是由开发了这个类的人来编写. 功能测试检验了特性是否依照预期工作(如:在一个博客系统里的提交操作).与单元测试相比,功能测试通常要高级一些,因为待测试的特性常常牵涉到多个类. 功能测试通常是由非常了解系统需求的人编写.(这个人既可以是开发者也可以是质量工程师). 测试驱动开发 以下展示的便是所谓的 测试驱动开发 (TDD) 的开发周期:
构建测试环境 Yii 提供的测试支持必要 PHPUnit 3.5+ 和 Selenium Remote Control 1.0+.请参照他们提供的文档来安装 PHPUnit 和 Selenium Remote Control. 当我们使用 yiic webapp 控制台命令来创建一个新的 Yii 应用时,它将会生成以下文件和目录供我们来编写和完成测试. testdrive/ 我们可以在控制台窗口执行以下命令来执行测试(无论是单元测试还是功能测试): % cd testdrive/protected/tests % phpunit functional/PostTest.php // 执行单个测试 % phpunit --verbose functional // 执行 'functional' 下的所有测试 % phpunit --coverage-html ./report unit 上面的最后一条命令将执行 unit 目录下的所有测试然后在 report 目录下生成出一份 code-coverage 申报. 注意要生成 code-coverage 申报必须安装并开启PHP的 xdebug 扩展 . 测试的引导脚本 让我们来看看 bootstrap.php 文件里会有些什么. 首先这个文件有点特殊,因为它看起来很像是 入口脚本,而它也正是我们执行一系列测试的入口. $yiit='path/to/yii/framework/yiit.php'; $config=dirname(__FILE__).'/../config/test.php'; require_once($yiit); require_once(dirname(__FILE__).'/WebTestCase.php'); Yii::createWebApplication($config); 如上所示,首先我们包括了来自 Yii 框架的 yiit.php 文件,它初始化了一些全局常量以及必要的测试基类.然后我们使用 test.php 这个配置文件来创建一个应用实例.如果你查看 test.php 文件,你会发现它是继承自 main.php 这个配置文件的,只不过它多加了一个类名为 [CDbFixtureManager] 的 fixture 应用组件. return CMap::mergeArray( require(dirname(__FILE__).'/main.php'),array( 'components'=>array( 'fixture'=>array( 'class'=>'system.test.CDbFixtureManager',),/* 去除以下注释可为测试提供一个数据库连接. 'db'=>array( 'connectionString'=>'DSN for test database',*/ ),) ); 当我执行那些涉及到数据库操作的测试时,我们应该提供一个测试专用的数据库以便测试执行不会干扰到正常的开发或者生产活动. 这样一来,我们纸必要去除上面 db 配置的注释,然后填写 connectionString 属性的用以连接到数据库的DSN(数据源名称)即可.
通过这样一个启动脚本,当我们执行单元测试时,我们便可以获得一个与服务需求类似的应用实例,而主要的不同就是测试拥有一个 fixture 管理器以及它专属的测试数据库. 定义特定状态(Fixtures) 自动测试必要被执行很多次.为了确保测试过程是可以重复的,我们很想要在一些可知的状态下进行测试,这个状态我们称之为 特定状态. 举个例子,在一个博客应用中测试文章创建特性,每次当我们进行测试时,与文章相关的表(例如. Post 表,Comment 表)应该被恢复到一个特定的状态下. PHPUnit 文档 已经很好的描述了一般的特定状态的构建. 而本节主要介绍怎样像刚才描述的例子那样构建数据库特定状态. 设置构建数据库的特定状态,这恐怕是测试以数据库为后端支持的应用最耗时的部分之一.Yii 引进的 [CBbFixtureManager] 应用组件可以有效的减轻这一问题.当进行一组测试的时候,它基本上会做以下这些事情: 在所有测试运行之前,它重置测试相关数据为可知的状态. return array( 'components'=>array( 'fixture'=>array( 'class'=>'system.test.CDbFixtureManager',); 然后我们在目录 protected/tests/fixtures下提供一个特定状态数据. 这个目录可以通过配置应用配置文件中的 [CDbFixtureManager::basePath] 属性指定为其他目录.特定状态数据是由多个称之为特定状态文件的PHP文件组合而成.每个特定状态文件返回一个数组,代表数据的一个特定表的初始行.文件名和表名相同.以下则是将 Post 表的特定状态数据存储于名为 Post.php 文件里的例子. <?php return array( 'sample1'=>array( 'title'=>'test post 1','content'=>'test post content 1','createTime'=>1230952187,'authorId'=>1,'sample2'=>array( 'title'=>'test post 2','content'=>'test post content 2','createTime'=>1230952287,); 正如我们所见,上面返回了两行数据. 每一行都表示一个数组,其键是表的字段名,其值则是对应的字段值.每行的索引都是称之为行别名的字符串(例如: simple1,simple2). 稍后当我们编写测试脚本的时候,我们可以方便地通过它的别名调用这行数据.你也许注意到了我们并未在上述特定状态中指定 id 字段的值. 这是因为 id 字段已经被定义为自增主键了,它的值也会在我们插入新数据的时候自动生成. 当 [CDbFixtureManager] 第一次被引用时,它会仔细检查所有的特定状态文件然后使用他们重置对应的表.它通过清空表,重置表主键的自增序列值,然后插入来自特定状态文件的数据行到表中来重置表. 有时候,我们可能不想在一套测试前重置特定状态文件里描述的每一个表,因为重置太多的特定状态文件可能需要很多时间.这种情况下,我们可以写一个PHP脚本来定制这个初始化过程.这个脚本应该被保留在存放特定状态文件的目录下,并命名为 init.php.当 [CDbFixtureManager] 检测到了这个脚本的存在,它将执行这个脚本而不是重置每一个表. 不喜欢使用默认方式来重置表也是可以的,例如: 清空表然后插入特定状态数据. 如果是这种情况,我们可以为指定的特定状态文件编写一个初始化脚本.这个脚本必需名称为表名+.init.php. 例如: Post 表的初始化脚本文件就是 Post.init.php. 当 [CDbFixtureManager] 发现了这个脚本,它将执行这个脚本而不是采用默认的方式去重置该表. Tip: 太多的特定状态文件大大延长了测试时间.因此,你应该只为那些在测试中数据会发生变化的表提供特定状态文件. 那些做为查找服务的表不会改变,因此不必要特定状态文件. 编程之家培训学院每天发布《在Mac OS上搭建PHP的Yii框架及相关测试环境》等实战技能,PHP、MYSQL、LINUX、APP、JS,CSS全面培养人才。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |