码迷,mamicode.com
首页 > Web开发 > 详细

PHP覆盖率测试工具小结

时间:2015-08-20 18:19:20      阅读:2013      评论:0      收藏:0      [点我收藏+]

标签:

一、写在最前

这篇文档是我对之前一段时间工作的总结和分享,自己也是第一次涉猎这方面的知识,肯定有遗漏和偏差,甚至“低级错误”,所以想起到抛砖引玉的作用,大家互相分享,共同进步。能够给同学们的工作带来些许启发,我也就很满足了。

 

二、覆盖率是什么?它能反映什么?

简单的说,覆盖率通常是指程序的执行过程中(即一个case),已执行的代码与可执行的代码的比值(或者与总代码行数的比值)。它能够从一个侧面反映出case的质量,即case是否做到对代码的完全覆盖。

 

三、PHP如何测试覆盖率?

1. Xdebug

Xdebug是PHP的一个扩展,了解PHP的同学一定不会对它陌生,非常强悍的调试助手,默认并没有开启,需要另外安装,不过多数情况下只需要在php.ini配置文件中开启即可。成功开启Xdebug后,我们便可以在程序中使用以下几个函数:

xdebug_start_code_coverage()    // 作用为开始统计覆盖率
xdebug_get_code_coverage()      // 作用为获取当前已统计信息
xdebug_stop_code_coverage()     // 作用为结束覆盖率统计

下面是个简单的例子:

<?php
  xdebug_start_code_coverage();
  // 注释、空行不会统计
  echo ‘hello world!‘;
  if ( false ) {
      echo "here is wrong\n";
  } else {
      echo "here is rigth\n";
  }
  $data = xdebug_get_code_coverage();
  xdebug_stop_code_coverage();
  // stop之后也不会统计

$data中保存了覆盖率信息,结果为:

1 (
2     [/Users/liufuxin/www/mars/index.php] => Array
3         (
4             [4] => 1
5             [6] => 1
6             [9] => 1
7             [12] => 1
8         )
9 )

可以看到,$data中保存了文件的相关信息,文件中第4、6、9、12行代码此次被执行了(状态码1表示执行)。本质上来说,基于这些信息,我们便可以统计代码的覆盖率了。各种框架也大多是基于Xdebug所获得的信息进行深加工。

但Xdebug的功能远非如此,再简单介绍下Xdebug的其他几个常用功能:

1.1 获取当前运行的文件、行号以及方法

<?php
    function fix_string() {
        echo "Called @ ".
        xdebug_call_file() . ":" .
        xdebug_call_line() . " from " .
        xdebug_call_function();
    }
fix_string();

// out : Called @ /Users/liufuxin/www/mars/index.php: 8 from {main}

1.2 获取程序当前已运行时间

<?php
    echo xdebug_time_index(), "\n"; 
    for ($i = 0; $i < 250000; $i++) {
        // do nothing
    } 
    echo xdebug_time_index();
?>

// out
// 0.0014429092407227
// 0.015676975250244

 1.3 追踪代码执行路径

可以在Xdebug的配置中将xdebug.auto_trace设置为on开启该功能,或者在程序中使用函数组xdebug_start_trace()和xdebug_stop_trace()来指定追踪的代码段。会自动在配置的输出目录中生成追踪文件,更多配置

1.4 Xdebug输出文件解析

当开启Xdebug后,会在指定的目录生成以“cachegrind.out.”开头的程序运行信息文件。它大致看起来是这样的:

version: 1
creator: xdebug 2.2.3
cmd: /Users/liufuxin/www/mars/index.php
part: 1
positions: line
events: Time
fl=php:internal
fn=php::xdebug_time_index
2 2
fl=php:internal
fn=php::xdebug_time_index
6 0

这时候我们就需要一些解析工具,推荐使用PHP实现的解析器webgrind,它安装简单,从浏览器打开后会自动探测xdebug输出目录,然后输出解析结果:

技术分享

可以清楚的看到程序执行过程中涉及的函数与其执行次数、耗时等基本信息。

 

2. PHPUnit

属于XUnit家族系列,用于对php代码进行单元测试,基于Xdebug可以方便快捷的对代码进行覆盖率测试,并生成直观的报表。看以下一个简单的例子,

准备两个类文件,BankAccount与对应的测试类BankAccountTest,代码如下:

<?php
    class BankAccount {
        protected $balance = 0;
        public function getBalance() {
            return $this->balance;
        }
        protected function setBalance($balance) {
            if ($balance >= 0) {
                $this->balance = $balance;
            } else {
                throw new BankAccountException;
            }
        }
    }
?>
<?php
    require_once ‘BankAccount.php‘;

    class BankAccountTest extends PHPUnit_Framework_TestCase {
        protected $ba;
        protected function setUp() {
            $this->ba = new BankAccount;
        }
        public function testBalanceIsInitiallyZero() {
            $this->assertEquals(0, $this->ba->getBalance());
        }
    }
?>

然后在终端使用phpunit命令执行测试文件,并指定为html输出格式和输出文件report。

phpunit --coverage-html ./report BankAccountTest.php

执行完毕后,通过浏览器查看report文件,便可以清晰的查看代码执行情况:

 技术分享

更多信息

 

3. codespy

与之前介绍的工具不同,codespy是纯php开发的轻量级覆盖率统计工具,并不依赖Xdebug。只需要在被测试代码前引入其库文件,便会自动在脚本执行完毕后生成测试报告。该工具是github上托管的开源工具(github大法好!)。这次我们以常用的PHP框架Thinkphp为例,在入口文件中引入库文件,同时进行一次API访问,查看生成的测试报告。入口文件如下:

<?php
    include ‘codespy.php‘;
    \codespy\Analyzer::$outputdir = ‘/Users/liufuxin/www/codespy‘;
    \codespy\Analyzer::$outputformat = ‘html‘;
 
  if(version_compare(PHP_VERSION,‘5.3.0‘,‘<‘)) {
    die(‘require PHP > 5.3.0 !‘);
  }
  define(‘APP_DEBUG‘,true);  
  define(‘NO_CACHE_RUNTIME‘,True);   require ‘./protected/ThinkPHP/ThinkPHP.php‘; ?>

Codespy使用起来非常方便,只需将库文件包含进来,同时设置报告的格式以及输出目录即可。然后我们访问API,查看报告。下图是本次访问所涉及的全部文件,大部分为框架代码:

 技术分享

我们只关注访问API的情况,点击具体Action查看详情:

技术分享

可以看出来,报告高亮的显示了执行的代码,以及两个维度的覆盖率,即6.78%的语句覆盖率(statement coverage)与2%的行覆盖率(line coverage)。

 

更多信息

 

4. PHPCoverage

河图上的工具,应用场景主要为满足页面级自动化测试,统计覆盖信息并生成报告,详情。可惜的是并没有提供任何文档,接口人也已离职,代码始终无法正常运行,不过通过查看其源代码,可以发现这个工具是基于phpcoverage这个开源项目进行的二次开发。需要依赖Xdebug和XML_Parser两个扩展。

 

5. Pika

同样为河图上的工具,特色是支持手工测试和生存周期控制,详情。其大致原理为在测试机安装并运行Pikagent程序,其可以与服务器进行交互,QA能够通过服务器的web界面控制整个测试流程,如下图所示:

技术分享 

详细阅读了该项目从最初的调研,到后期各种会议的文档,项目最早的目标便是实现百度PHP代码的覆盖率测试工具,希望能够结合手动与自动两种工作方式,同时实习测试周期的可控,即报告中可以包含多个case的运行情况。

但目前核心的中控机也已无法访问,项目也宣布停止维护,比较可惜,不过从他的文档中也可以吸收不少借鉴,比如对我厂及国内当时PHP覆盖率方面的调研(2009年),关于报告生成、性能优化、交互设计等都有一定的讨论和记录。

 

四、主要方案比较

1、方案总体比较

 

方案

缺点

优点

Xdebug

1. 需要额外安装扩展

2. 输出解析复杂

1. 性能最优

2. 代码插入灵活

3. 功能丰富

PHPUnit

1. 需要额外安装扩展

2. 必须使用PHPUnit框架重新编写case

3. 只能进行单元测试

1. 规范化

2. 结果解析最优

codespy

1. 运行速度最慢

2. 功能单一

1. 代码插入简单

2. 开源,易于扩展

 

2、性能对比

更多的时候我们是不希望重新编写case和额外的代码,大家的测试场景也主要集中在API测试,PHPUnit更适合RD进行单元测试,所以本文将通过一个小实验比较下Xdebug和codespy的性能。

 

首先,我们以Thinkphp为例,计算两者在进行一次覆盖率统计中的耗时。访问一个空置的接口,并统计平均耗时。

方案

实验次数

平均时间(秒)

Xdebug

100

0.05

codespy

100

0.91

 

从表中可以看到,Xdebug基本不会造成太大的性能损耗,而codespy却有将近20倍的额外耗时!

真的相差这么多?带着疑问,进行了另一个对比测试,这次我们在API中进行一次比较耗时的操作,从远程接口获取数据(几百数量级)解析并写入数据库,结果如下:

方案

实验次数

API耗时(秒)

平均时间(秒)

Xdebug

100

4.42

4.48

codespy

100

4.51

5.41

比较意外,两者的性能损耗并不是线性增长的,Xdebug的时间基本保持在0.05秒左右,而codespy则基本在1秒左右。但是codespy比xdebug性能更差是可以确定的,而codespy在实际生产环境中表现到底如何,会在实际使用过后再作分享。

 

综上,不同的方案有其所适合的不同场景。Xdebug适用于测试需求复杂的大型项目,例如函数覆盖、类覆盖等,同时其也很容易与第三方工具交互;PHPUnit主要用于模块的单元测试,同时其规范的case管理也适合大型项目;codespy以其轻量级与简单易扩展,能够胜任大多数的小项目的覆盖率测试需求。

 

五、最后

以上便是我经过调研学习的一点收获,希望能够对大家起到一定作用,欢迎拍砖。另外值得一提的是,刚开始还是想到Hetu上搜搜,结果比较失望,仅有的几个工具不是“年久失修”,就是没有文档,上手困难,希望百度人能够更好的总结分享,维护好我们的知识储备。

 

六、最最后

下面贴出一些相关的资源,方便大家搭建环境,查阅文档。

PHPUnit安装Mac请看这里,主要介绍PHPUnit如何安装。

PHPUnit实例,PHPUnit的一篇更详细的介绍日志。

PHPUnit在线文档,中文在线文档,非常详细。

Xdebug配置,关于Xdebug的详细配置介绍。

Codespy fork,codespy的github地址。

PHP覆盖率测试工具小结

标签:

原文地址:http://www.cnblogs.com/liufxlucky365/p/4745656.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!