清道夫 发表于 2013-6-20 10:41:22

CI 的 单 元 测 试

      最近几周一直在学习CI框架,利用CI框架可以方便快速地建议自己的网站。而CI还有一个意思就是持续化集成,所以就要求测试也自动化。但是我搜了一下,这方面的文档不多,实在没有办法,就把CI与单元测试相关的源码给全看了一下,虽然不是太懂,但是已经可以自己写测试用例了,现在总结一下,希望对大家有所帮助。初步接触CI的单元测试      CI是利用PHPUNIT进行测试的,而框架里面自带的也有写好的测试用例,大家可以拿来练一下手.(1)安装PHPUNIT,具体安装方法,在不同的操作系统下也不相同,网上有很多方法,可以参照一下。安装完成后会显示下面的效果,说明安装成功:    C:\>phpunit --versionPHPUnit 3.6.11 bySebastian Bergmann.(2)进入你放置CI代码下的tests文件夹下,运行phpunit命令。D:\DinerSystem\Sinafood\tests>phpunitPHPUnit3.6.11 by Sebastian Bergmann.Configurationread from D:\DinerSystem\Sinafood\tests\phpunit.xml..................Time:1 second, Memory: 4.00Mb 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文件中的数据格式如下:现有测试数据表:ff_phone_carrier(name   varchar(255),txt_address    varchar(255),   txt_message_length      int(11));            
很显然原工程中的表名为:phone_carrier,现在测试数据文件中:phone_carrier_fixt.yml:1:                         //此为第一条记录    name: 'Verizon'          //对应字段的值    txt_address: '@vzpix.com'    txt_message_length: 1602:    name: 'AT&T'    txt_address: '@mms.att.net'    txt_message_length: 160(3)测试用例结构A,Controller测试用例结构<?php/** * @group Controller */class SomeControllerTest extendsCIUnit_TestCase{publicfunction setUp(){      //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/** * @group Model */class PhoneCarrierModelTest extendsCIUnit_TestCase{protected$tables = array(      '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
<?phpclass showmenu extends CI_Controller {      public function __construct()       {                   parent::__construct();               $this->load->model(showmenu _m');       }             //查询显示所有数据       public function index()       {             $data['query']=$this-> showmenu _m->getfoodlist();             $this->load->view(showmenuview,$data);       }}?>
(2)model: showmenu_m.php
<?phpclass showmenu _m extends CI_Model {      function __construct()    {      $this->load->database();   }    //获取food表中的所有记录   function getfoodlist()   {                    $this->db->select('*')->from('food');         $query= $this->db->get();              return $query->result();    }}?>
(3)view:showmenuview.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),namevarchar(45),owner         varchar(45),price   int(11),countint(11) );2,测试战争(1)建立测试数据库foodfeed_test,对应的表:ff_food,表结构同正式表,表中无任何数据。(2)在tests/fixtures中建测试数据文件food_fixt.yml,内容如下:## YAML Template.1: id: 1 name: "鱼香肉丝" owner: "面香" price: 15 count: 122: id: 2 name: "红烧带鱼" owner: "大食代" price: 28 count: 1 (3)创建测试文件   A,对controller的测试:
<?phpclass ShowMenuTestextends CIUnit_TestCase{              protected $tables = array(                   '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);//判断筛选的结果      $this->assertSame('28',$arr);                                   }      }?>
B,对model进行测试
<?phpclass ShowMenuModelTest extendsCIUnit_TestCase{      protected $tables = array(            'ff_food'=> 'food'       );                 private$_pcm;              publicfunction __construct($name = NULL, array $data = array(), $dataName = '')       {            parent::__construct($name,$data, $dataName);       }              publicfunction setUp()       {//装载测试数据            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->price);//检测返回的结果      $this->assertEquals(28, $actual->price);                   }        }?>
(4)运行测试用例D:\DinerSystem\Sinafood\tests>phpunitPHPUnit 3.6.11 by Sebastian Bergmann.Configuration read fromD:\DinerSystem\Sinafood\tests\phpunit.xml..................Time: 4 seconds, Memory: 4.00MbD:\DinerSystem\Sinafood\tests> (5)排查测试中存在的错误      测试用例在运行过程中会出现各种错误的情况,这个时候就需要你对其进行排查。我建议:(a)对要检测的结果进行输出,以方便知道哪儿发生了错误。(b)程序中使用CI框架标准的数据操作函数,否则也会出错。其他的情况也会非常多,就不一一列举了,具体问题具体分析吧!

清道夫 发表于 2013-6-20 10:44:07

:(,我设置成PHP代码后,程序咋这么乱呢?

Hex 发表于 2013-6-20 13:58:11

清道夫 发表于 2013-6-20 10:44 static/image/common/back.gif
,我设置成PHP代码后,程序咋这么乱呢?

把代码标签里的其他标签都去掉就行了。

清道夫 发表于 2013-6-20 14:03:16

Hex 发表于 2013-6-20 13:58 static/image/common/back.gif
把代码标签里的其他标签都去掉就行了。

发过的帖子不能修改啊?

Hex 发表于 2013-6-20 14:07:33

清道夫 发表于 2013-6-20 14:03 static/image/common/back.gif
发过的帖子不能修改啊?

可以修改吧,你没有编辑按钮吗?

清道夫 发表于 2013-6-20 14:40:31

Hex 发表于 2013-6-20 14:07 static/image/common/back.gif
可以修改吧,你没有编辑按钮吗?

没有,大概有等级限制吧?

★♂翼☆ 发表于 2013-7-1 16:49:43

大哥,改下格式把,好乱

清道夫 发表于 2013-7-2 11:23:58

★♂翼☆ 发表于 2013-7-1 16:49 static/image/common/back.gif
大哥,改下格式把,好乱

我没有编辑权限啊!!

khalilfiona 发表于 2013-8-6 13:02:34

看起来好强,先Mark!

绮绮 发表于 2014-10-10 11:53:44

楼主,我想问个问题,我在测试我的model层代码,但是一些可以正常运行,一些显示加载失败: Error: 500 Message: Unable to locate the model you have specified: ordercommentcomplaint。您知道是什么问题么?不用ciunit测试我的代码是完全可以跑通的。一用ciunit就加载不成功了。
页: [1]
查看完整版本: CI 的 单 元 测 试