最近几周一直在学习CI框架,利用CI框架可以方便快速地建议自己的网站。而CI还有一个意思就是持续化集成,所以就要求测试也自动化。但是我搜了一下,这方面的文档不多,实在没有办法,就把CI与单元测试相关的源码给全看了一下,虽然不是太懂,但是已经可以自己写测试用例了,现在总结一下,希望对大家有所帮助。 初步接触CI的单元测试 CI是利用PHPUNIT进行测试的,而框架里面自带的也有写好的测试用例,大家可以拿来练一下手. (1)安装PHPUNIT,具体安装方法,在不同的操作系统下也不相同,网上有很多方法,可以参照一下。安装完成后会显示下面的效果,说明安装成功: C:\>phpunit --version PHPUnit 3.6.11 bySebastian Bergmann. (2)进入你放置CI代码下的tests文件夹下,运行phpunit命令。 D:\DinerSystem\Sinafood\tests>phpunit PHPUnit3.6.11 by Sebastian Bergmann. Configurationread from D:\DinerSystem\Sinafood\tests\phpunit.xml .................. Time:1 second, Memory: 4.00Mb [30;42m[2KOK(18 tests, 24 assertions) [0m[2K D:\DinerSystem\Sinafood\tests> 你运行结果中的tests和assertions个数可能和我的不一样,因为我现在的结果加了其他的测试用例,只要出来这个结果,说明测试可以进行了。 CI单元测试结构介绍 (1)测试文件结构 在框架根目录下的tests文件夹中有以下几个文件夹,其作用如下: Controllers:存放对Application中的controller中的文件进行测试。 Fixtures:存放测试数据文件yml及其他测试(暂时没有搞明白)。 Helpers:存放对Application中的helpers中的文件进行测试。 Libs:存放对Application中的libs中的文件进行测试。 Models:存放对Application中的models中的文件进行测试。 System:存放对Application中的system中的文件进行测试。 该文件夹下还有如generate,generate.php, getops.php, holder 及phpunit.xml在写测试用例的时候我们不用修改,暂忽略之。 在application文件夹下还有一个third_party的文件夹,这个里面有CIUnit文件夹,里面存放着生成和回收测试数据的Fixture.php,还有其他进行测试相关驱动的文件,目前我没有研究它们的工作方法。 (2)测试数据库 如果你要测试的程序有数据操作的话,在测试之间要先往数据库中存放一些儿测试数据,测试完成之后要清除数据,不过这些儿工作CI框架已经帮你完成,你只要建测试数据库及对应的表就行了。测试数据库必须以“_test”结尾,其连接配置在:application/config/testing/database.php中设置,方法和CI的正常配置一样。如果在文件中配置了$db['default']['dbprefix']= 'ff_';项,则要注意:测试表必须以“ff_”开头。 测试数据存放在tests/fixtures文件夹中,测试文件以”原项目中的表名_fixt.yml”命名,否则程序无法读取其中的数据。Yml文件中的数据格式如下: 现有测试数据表: SQL复制代码 ff_phone_carrier([/align][align=LEFT]name VARCHAR(255),[/align][align=LEFT]txt_address VARCHAR(255),[/align][align=LEFT] txt_message_length INT(11));[/align] 复制代码
很显然原工程中的表名为:phone_carrier,现在测试数据文件中:phone_carrier_fixt.yml: 1: //此为第一条记录 name: 'Verizon' //对应字段的值 txt_address: '@vzpix.com' txt_message_length: 160 2: name: 'AT&T' txt_address: '@mms.att.net' txt_message_length: 160 (3)测试用例结构 A,Controller测试用例结构 PHP复制代码 <?php[/i][/align][align=left][i]/** * @group Controller */[/i][/align][align=left][i]class SomeControllerTest extendsCIUnit_TestCase[/i][/align][align=left][i]{[/i][/align][align=left][i] publicfunction setUp()[/i][/align][align=left][i] {[/i][/align][align=left][i] //Set the tested controller $this->CI= set_controller('welcome');//设置要测试的controller,本例为welcome } publicfunction testWelcomeController() { // 调用被测试的Controller中的方法 index() $this->CI->index(); //获得输出结果 $out= output(); //对结果进行检测 $this->assertSame(0,preg_match('/(error|notice)/i', $out)); } } 复制代码
B,Model测试用例结构: PHP复制代码
<?php[/i][/align][align=left][i]/** * @group Model */[/i][/align][align=left][i]class PhoneCarrierModelTest extendsCIUnit_TestCase[/i][/align][align=left][i]{[/i][/align][align=left][i] protected$tables = array([/i][/align][align=left][i] 'ff_phone_carrier'=> 'phone_carrier' //设置数据表:测试用例表对=>正式表 ); private$_pcm; publicfunction __construct($name = NULL, array $data = array(), $dataName = '') { parent::__construct($name,$data, $dataName); } publicfunction setUp() {//测试开始执行的方法 parent::setUp(); /* 引用要测试的model,并将测试数据写入测试库的对应该表中。 */ $this->CI->load->model('Phone_carrier_model'); $this->_pcm= $this->CI->Phone_carrier_model; } publicfunction tearDown() {//测试结束执行的方法 parent::tearDown(); } //------------------------------------------------------------------------ /** * @dataProvider GetCarriersProvider //设置数据提供者 */ publicfunction testGetCarriers(array $attributes, $expected) { //具体的测试方法 $actual= $this->_pcm->getCarriers($attributes); $this->assertEquals($expected,count($actual)); } publicfunction GetCarriersProvider() {//提供检测数据的方法,也可以直接写数据 returnarray( array(array('name'),5) ); } } 复制代码实战演习 1,要测试的项目 现有一小网页显示数据库foodfeed中的一个表单food中的数据,各个文件内容如下: (1) Controller :showmenu.php PHP复制代码
<?php[/align][align=left]class showmenu extends CI_Controller {[/align][align=left] public function __construct()[/align][align=left] {[/align][align=left] parent::__construct();[/align][align=left] $this->load->model(showmenu _m'); } //查询显示所有数据 public function index() { $data['query']=$this-> showmenu _m->getfoodlist(); $this->load->view(showmenuview,$data); } } ?> 复制代码
(2)model: showmenu_m.php PHP复制代码
<?php[/align][align=left]class showmenu _m extends CI_Model [/align][align=left]{ [/align][align=left] function __construct()[/align][align=left] {[/align][align=left] $this->load->database();[/align][align=left] }[/align][align=left] //获取food表中的所有记录 function getfoodlist() { $this->db->select('*')->from('food'); $query= $this->db->get(); return $query->result(); } } ?> 复制代码
(3)view:showmenuview.php PHP复制代码
<htmlxmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type"content="text/html; charset=utf-8" /> <title>推荐菜品展示</title> </head> <body> <div> <table border=1> <tr> <td>菜品ID</td> <td>菜品名称</td> <td>单价</td> <td>餐馆</td> <td>数量</td> </tr> <?php foreach ($query as $rows):?> <tr> <td><?=$rows->id?></td> <td><?=$rows->name?></td> <td><?=$rows->price?></td> <td><?=$rows->owner?></td> <td> <?=$rows->count?></td> </tr> <?php endforeach;?> </table> </div> </body> </html> 复制代码
(4)程序所用的数据表结构如下: Foodfeed.food( id int(11), name varchar(45), owner varchar(45), price int(11), count int(11) ); 2,测试战争 (1)建立测试数据库foodfeed_test,对应的表:ff_food,表结构同正式表,表中无任何数据。 (2)在tests/fixtures中建测试数据文件food_fixt.yml,内容如下: ## YAML Template. 1: id: 1 name: "鱼香肉丝" owner: "面香" price: 15 count: 12 2: id: 2 name: "红烧带鱼" owner: "大食代" price: 28 count: 1 (3)创建测试文件 A,对controller的测试: PHP复制代码
<?php[/align ][align =left ]class ShowMenuTestextends CIUnit_TestCase [/align ][align =left ]{ [/align ][align =left ] protected $tables = array([/align ][align =left ] 'ff_food' => 'food' //设置表对应关系 ); private $_pcm; public function __construct($name =NULL, array $data = array(), $dataName = '') { parent::__construct($name,$data, $dataName); } public function setUp() { //装载测试数据 parent::setUp(); $this->CI->load->model('showmenu_m'); $this->_pcm =$this->CI-> showmenu_m; // Set the tested controller $this->CI =set_controller(“showmenu”); } //测试showmenu的index() public function testIndexController() { // Call the controllersmethod $this->CI->index(); // Fetch the buffered output $out = output(); // Check if the content is OK preg_match_all("/<td>(.*)<\/td>/isU",$out,$arr); //对返回的数据进行筛选 //print_r($arr); $this->assertSame('15',$arr[1][7]);//判断筛选的结果 $this->assertSame('28',$arr[1][37]); } } ?> 复制代码
B,对model进行测试 PHP复制代码
<?php[/size][/font][/align][align=left][font="][size=10.5pt]class ShowMenuModelTest extendsCIUnit_TestCase[/size][/font][/align][align=left][font="][size=10.5pt]{[/size][/font][/align][align=left][font="][size=10.5pt] protected $tables = array([/size][/font][/align][align=left][font="][size=10.5pt] 'ff_food'=> 'food'[/size][/font][/align][align=left][font="][size=10.5pt] ); [/size][/font][/align][align=left][font="][size=10.5pt] private$_pcm;[/size][/font][/align][align=left][font="][size=10.5pt] [/size][/font][/align][align=left][font="][size=10.5pt] publicfunction __construct($name = NULL, array $data = array(), $dataName = '')[/size][/font][/align][align=left][font="][size=10.5pt] {[/size][/font][/align][align=left][font="][size=10.5pt] parent::__construct($name,$data, $dataName);[/size][/font][/align][align=left][font="][size=10.5pt] }[/size][/font][/align][align=left][font="][size=10.5pt] [/size][/font][/align][align=left][font="][size=10.5pt] publicfunction setUp()[/size][/font][/align][align=left][font="][size=10.5pt] {//装载测试数据 parent::setUp(); $this->CI->load->model('recommand_m'); $this->_pcm= $this->CI->recommand_m; } publicfunction tearDown() { parent::tearDown(); } //测试全部数据显示 public function testmodelindex() { $actual = $this->_pcm->getfoodlist( ); $this->assertEquals(15,$actual[0]->price);//检测返回的结果 $this->assertEquals(28, $actual[6]->price); } } ?> 复制代码
(4)运行测试用例 D:\DinerSystem\Sinafood\tests>phpunit PHPUnit 3.6.11 by Sebastian Bergmann. Configuration read fromD:\DinerSystem\Sinafood\tests\phpunit.xml .................. Time: 4 seconds, Memory: 4.00Mb [30;42m[2KOK (18 tests, 24 assertions) [0m[2K D:\DinerSystem\Sinafood\tests> (5)排查测试中存在的错误 测试用例在运行过程中会出现各种错误的情况,这个时候就需要你对其进行排查。我建议:(a)对要检测的结果进行输出,以方便知道哪儿发生了错误。(b)程序中使用CI框架标准的数据操作函数,否则也会出错。其他的情况也会非常多,就不一一列举了,具体问题具体分析吧!
|