用户
 找回密码
 入住 CI 中国社区
搜索
查看: 24835|回复: 29
收起左侧

PHPUnit与CI结合进行单元测试以及代码覆盖率

[复制链接]
发表于 2012-3-31 16:08:23 | 显示全部楼层 |阅读模式
本帖最后由 fltn03 于 2014-8-13 14:56 编辑

         目前有一个项目是基于CI开发,但项目完成后上级要求要进行单元测试并出具代码覆盖率。
         我也是刚接触PHPUnit,对于单个类的函数进行测试还可以进行。但将单元测试运用到实际的项目中实就没了头绪,因为在项目中,一个类中的函数都会与其他类中的函数有关联,如果进行单元测试时又必须先引入被关联的类文件。在网上查找关于PHPUnit与CI结合的单元测试信息又是寥寥无几,在本论坛搜索也没有找到比较详细的例子。http://codeigniter.org.cn/forums/thread-941-1-1.html
这篇文章也没看明白!所以在此与大家计论一下,看有没有比较合适的方法。
        稍待的问一下:
        1、PHPUnit是进行命令行执行,那等运行的测试类应该放在哪里?
        2、编写测试类时是否需要加载CI所有的需要用到的文件呢?
------------------------------------------------------------------------------------------------------
        如果有没描述清楚的我会随时补充!希望有遇到相同问题的朋友一起讨论讨论!更希望高手指点指点!

非常感谢@frankth推荐给大家一个phpunit与ci集成的例子:https://github.com/fmalk/codeigniter-phpunit


 楼主| 发表于 2012-4-8 19:20:44 | 显示全部楼层
本帖最后由 fltn03 于 2012-4-8 19:25 编辑

在进行PHPUnit测试之前需要先准备好一些东西:
1、待测试的代码
2、已安装好了PHPUnit(最好将phpunit设置成环境变量)
3、测试需要用到的工具包
-------------------------------------------------------------------------------
首先来说一下工具包中的目录结构:
application---|
                    config---------|
                                         testing--|..........该目录中给出一个数据库配置文件database.php
                     models--------|......................该目录中给出一个模型的示例phone_carrier_model.php
                     third_party---|
                                          CIUnit--|..........测试包,包中结合了PHPunit
tests-----------|...........................................将待测试的类写到相应的位置
                     controllers----|......................测试控制器
                     fixtrues--------|
                     helpers--------|......................测试辅助函数
                     libs--------------|.....................测试libraries中的库类
                     models---------|.....................测试models中的类
                     system---------|
                     generate.php
                     getops.php
                     phpunit.xml
需要说明的是:
a、tests文件夹与application为同级目录
b、将工具包中application/config/目录下的testing文件夹放到项目中相对应的application/config/目录下
c、将工具包中application/models/目录下的phone_carrier_model.php文件放到项目中相对应的application/models目录下,该文件只是一个示例
d、将工具包中application/third_party/目录下的CIUnit文件夹放到项目中相对应的application/third_party/目录下
e、将工具包中tests文件夹放到项目中与application同级别的目录下
f、准备好一个专供CIUnit使用的数据库ciunit_test,注意数据库名称必须是以“_test”结尾,工具包中提供了一个名为phone_carrier_model.php的文件,该文件中使用到了数据库,其数据库配置信息就对应于application/config/testing/目录下的database.php文件,所以需要在该数据库下创建一个表,名为phone_carrier,其SQL语句如下:
SQL复制代码
CREATE TABLE IF NOT EXISTS `phone_carrier` (
  `name` VARCHAR(255) NOT NULL,
  `txt_address` VARCHAR(255) NOT NULL,  `txt_message_length` INT(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
复制代码

-------------------------------------------------------------------------------
所以准备工作完成后,下面就开始进行测试(以下以windows系统为例进行讲解,我本机安装的是集成环境xampp,所以里面自带了phpunit,并为phpunit设置了环境变量)。
首先打开cmd.exe,进入到待测试项目下的tests目录:
D:\xampp\htdocs\Study\CodeIgniter2.1.0>
D:\xampp\htdocs\Study\CodeIgniter2.1.0>cd tests
在tests目录下输入命令“phpunit”回车即可:
D:\xampp\htdocs\Study\CodeIgniter2.1.0\tests>phpunit
如果显示以下信息,表示工具包已经安装成功:
PHPUnit 3.5.14 by Sebastian Bergmann.
...........
Time: 2 seconds, Memory: 7.50Mb
<-[30;42m<-[2KOK <11 tests, 7 assertions>
<-[0m<-2K
说明:
显示信息的第一行表示使用的phpunit版本;
第二行表示进行单元测试时的执行结果,“.”表是断言成功,出现的还有可能是其它的符号,比如“F”、“E”、“S”等(更多信息请自行查看PHPUnit相关资料);
第三行表示代码的执行时间以及内存的使用情况;
第四行表示执行了11个测试,7个断言;
-------------------------------------------------------------------------------
所有东西安装成功后就开始做单元测试。
在tests目录下有controllers、fixtures、helpers、libs、models和system等文件夹,这里的每个文件夹都对应着项目中application目录下的controllers、helpers、libraries和models等。所以只需要将测试文件写在tests目录下的对应文件夹中。
为了更好的测试,我们先将tests目录下的controllers、helpers、libs、models和system文件夹下的内容清空(工具包中tests目录下的各文件夹中其实已经给出了测试的例子,告诉你如何去写单元测试)。
下面以项目中controllers目录下的welcome.php为例:
PHP复制代码
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class Welcome extends CI_Controller {
/**
  * Index Page for this controller.
  *
  * Maps to the following URL
  *   http://example.com/index.php/welcome
  * - or -  
  *   http://example.com/index.php/welcome/index
  * - or -
  * Since this controller is set as the default controller in
  * config/routes.php, it's displayed at http://example.com/
  *
  * So any other public methods not prefixed with an underscore will
  * map to /index.php/welcome/<method_name>
  * @see http://codeigniter.com/user_guide/general/urls.html
  */

public function index()
{
  $this->load->view('welcome_message');
}
 
public function test($a)
{
  if($a >= 0)
  {
   return true;
  }
  else
  {
   return false;
  }
}
}
/* End of file welcome.php */
/* Location: ./application/controllers/welcome.php */
复制代码

在welcome控制器中增加了一个test方法。
然后在tests/controllers目录下新建一个WelcomeTest.php文件,内容如下:
PHP复制代码
<?php
/**
* @group Controller
*/

class WelcomeTest extends CIUnit_TestCase
{
public function setUp()
{
  // Set the tested controller
  $this->CI = set_controller('welcome');
}
 
public function testIndex()
{
  // Call the controllers method
  $this->CI->index();
 
  // Fetch the buffered output
  $out = output();
 
  // Check if the content is OK
  $this->assertSame(0, preg_match('/(error|notice)/i', $out));
}
 
public function testTest()
{
  $result = $this->CI->test(5);
 
  //断言
  $this->assertEquals(true,$result);
}
 
public function testTest1()
{
  $result = $this->CI->test(0);
 
  //断言
  $this->assertEquals(true,$result);
}
 
public function testTest2()
{
  $result = $this->CI->test(-5);
 
  //断言
  $this->assertEquals(false,$result);
}
}
 
复制代码

说明:在WelcomeTest.php中写了四个测试函数,分别对welcome.php控制器中的index()和test()函数进行了测试。
接下来在cmd.exe下执行命令phpunit(注意是在tests目录下执行):
D:\xampp\htdocs\Study\CodeIgniter2.1.0\tests>phpunit
显示结果如下:
PHPUnit 3.5.14 by Sebastian Bergmann.
....
Time: 0 seconds, Memory: 6.00Mb
<-[30;42m<-[2KOK <4 tests, 4 assertions>
<-[0m<-2K
说明:这里有四个测试和断言,结果都是正确。
至此,完成了一个控制器的测试工作,如果想对models或是libraries中的类进行测试,方法与上面类似,也可以查看工具包中给出的示例。
-------------------------------------------------------------------------------
接下来就查看一下单元测试的覆盖率问题。
其实完成单元测试,也就完成了覆盖率。以刚才的例子来说,将覆盖率以html形式生成并放在coverage_report目录下则只需要在cmd.exe中执行phpunit --coverage-html(如果对phpunit --coverage-html命令不熟悉,请查阅相关资料)即可:
D:\xampp\htdocs\Study\CodeIgniter2.1.0\tests>phpunit --coverage-html coerage_report
显示结果如下:
PHPUnit 3.5.14 by Sebastian Bergmann.
....
Time: 1 seconds, Memory: 6.75Mb
<-[30;42m<-[2KOK <4 tests, 4 assertions>
<-[0m<-2K
Generating code coverage report, this may take a moment.
与此同时,在tests目录下会有coerage_report文件夹,里面的内容便是单元测试的覆盖率。
-------------------------------------------------------------------------------
至此完成了PHPUnit与CI结合的单元测试以及覆盖率。无法贴图,所以无法看效果......

以上信息中如果有不正确的地方,希望各位指正!
正是因为发帖无助,所以才请了高人指点,希望能帮助到大家。
原文网址:http://d.hatena.ne.jp/Kenji_s/20120117/1326763908






发表于 2014-7-20 18:04:15 | 显示全部楼层
感觉你写的比较乱。刚刚下载测试后还发现很多路径基本上运行不了。
在DumpTest.php 中的路径 require_onc dirname(dirname(__FILE__))."../spyc.php";
改成:require_once dirname(dirname(__FILE__))."/spyc.php";

推荐给大家一个phpunit与ci集成的例子:
https://github.com/fmalk/codeigniter-phpunit

评分

参与人数 1威望 +2 收起 理由
fltn03 + 2

查看全部评分

发表于 2014-5-4 12:45:04 | 显示全部楼层
求助: 我一进入 test 目录,运行phpunit  就报错如下:
G:\ProgramSouce\PHP\Dev\91_CI_phpunit_test\tests>phpunit
[CIUnit] PHP Error: Warning - require_once(PHPUnit/Autoload.php): failed to open
stream: No such file or directory File Path: CIUnit/bootstrap_phpunit.php (line
: 260)
请各位帮忙,谢谢了
发表于 2012-4-8 19:35:15 | 显示全部楼层
不错。
发表于 2012-9-20 16:13:27 | 显示全部楼层
fltn03 发表于 2012-4-8 19:20
在进行PHPUnit测试之前需要先准备好一些东西:
1、待测试的代码
2、已安装好了PHPUnit(最好将phpunit设置成 ...

在tests 里面测试的时候  报出来“your system folder path does not appear to be set correctly.Please open the flowing file and correct this: bootstrap_phpunit.php”   说这个文件里面的路径设置错误,我是新手,请教下怎么设置,自己捣腾了半天没调出来
 楼主| 发表于 2012-9-25 10:10:22 | 显示全部楼层
い微风ァ飘叶 发表于 2012-9-20 16:13
在tests 里面测试的时候  报出来“your system folder path does not appear to be set correctly.Please ...

你找到bootstrap_phpunit.php文件,查看第62行和170行至173行的代码:
62行:
PHP复制代码
$system_path = dirname(__FILE__) . '/../../../system';
复制代码

170行至173行:
PHP复制代码
 
        if ( ! is_dir($system_path))    {
                exit("Your system folder path does not appear to be set correctly. Please open the following file and correct this: ".pathinfo(__FILE__, PATHINFO_BASENAME));
        }
复制代码

说明是你的system目录设置的不正确.
可能原因:
1、调整了CI原有的目录结构,如果这是样,你需要修改$system_path的路径;

发表于 2012-10-12 11:51:45 | 显示全部楼层
请问一下 如果的我的在 welcome.php 添加一个方法
function myfunc()
{
     $data = $this->input->post('num');
     if($data > 0)
     {
          return true;
      }
      return false;
}


在welcome.php中写个
function testMyfunc()
{
  $result = $this->CI->myfunc();  ////这个myfunc方法要怎么测试,怎么传递参数到myfunc?
  $this->assertEquals(true,$result);
}
 楼主| 发表于 2012-10-13 15:20:20 | 显示全部楼层
去年明日 发表于 2012-10-12 11:51
请问一下 如果的我的在 welcome.php 添加一个方法
function myfunc()
{
PHP复制代码
function testMyfunc()
{
  $result = $this->CI->myfunc();  //这个myfunc方法要怎么测试,怎么传递参数到myfunc?
  //模拟传入参数
 $_POST['表单字段'] = '对应的值';
  $this->assertEquals(true,$result);
}
复制代码

发表于 2012-10-15 13:01:51 | 显示全部楼层
去年明日 发表于 2012-10-12 11:51
请问一下 如果的我的在 welcome.php 添加一个方法
function myfunc()
{

cli的时候,无法获取web变量的,测试的时候先赋值
或者做成环境变量,或者phpunit ENV=xxx test.php测试
发表于 2012-10-15 13:02:30 | 显示全部楼层
fltn03 发表于 2012-10-13 15:20

$_POST应该在前
 楼主| 发表于 2012-10-15 14:40:51 | 显示全部楼层
大道达人 发表于 2012-10-15 13:02
$_POST应该在前

谢谢你!
是我的失误,$_POST应该放在待执行的函数之前.
应该是这样:
PHP复制代码
 
function testMyfunc()
{
    $_POST['表单字段'] = '对应的值';
    $result = $this->CI->myfunc();
    $this->asserEquals(true, $result);
}
 
复制代码

本版积分规则