澳门新浦京手机版Windows和Linux中php代码调试工具Xdebug的安装与配置详解_php实例_脚本之家

1. 关于代码覆盖率

衡量代码覆盖率有很多种层次,比如行覆盖率,函数/方法覆盖率,类覆盖率,分支覆盖率等等。代码覆盖率也是衡量测试质量的一个重要标准,对于黑盒测试来说,如果你不确定自己的测试用例是否真正跑过了系统里面的每一行代码,在测试的完整性上总要打些折扣。因此,业界几乎对各种编程语言都有自己的一套代码覆盖率解决方案。世界上最美的语言PHP当然也不例外。PHPUnit和Spike
PHPCoverage提供了一套基于xdebug的代码覆盖率测试方案。在本文中,我将针对自己碰到的特定业务场景,讲述一下自己进行PHP代码函数覆盖率测试的解决方案。

一、为什么需要Debugger?

今天我就就自己对XDebug使用的一些体验做一小段分享。XDebug也是因为需要是用来生成覆盖率分析文件才安装的,刚接触不久,平时用的也不是很频繁,但是这个的确是一个好工具,如果想要依赖它来分析程序的性能还是需要自己亲手去试试。具体它有多好,请听我一一道来。

2. 业务背景

假设我们在线开发了一个网站,交给业务测试的同事去进行功能测试。那他们是怎么测试的呢?通常情况下,无非是开发人员把网站部署好了,然后测试人员把网上所有功能都试用一遍,包括一些异常使用情况。对于业务测试来说,只要我把所有的功能点都测了,把所有异常使用情况也测到了,那就完成了。但是对于开发来说,我比较好奇的是,你是否把我写的所有代码都跑到了?会不会存在一些代码,只有在很特殊的情况下才能触发,而你从来没有测到过这些情况?这时,可能就需要代码覆盖率来出马了。

其实我首先想到了xdebug来测试覆盖率,只需要两三个函数即可,如下:

xdebug_start_code_coverage(); //开始收集代码行覆盖情况

xdebug_get_code_coverage(); //获取截至目前所跑过的代码文件名和行号

xdebug_stop_code_coverage(); //停止收集代码行覆盖情况

xdebug提供的接口可以用于测试行覆盖率,这是否能满足要求呢?其实,行覆盖率颗粒度有点细,实际项目中,开发人员可能会对代码进行微调。比如,这次测试,你跑过了A.php文件的第10行,但是我有一天对A.php进行了微调,在A.php第9行和第10行之间又加了两行代码。于是,原来的第10行变为了第12行,而xdebug的行覆盖信息只记录了行号……这样之前的数据岂不是不准确了么。。。考虑再三,我觉得函数覆盖是个不错的颗粒度。在相对成熟的项目中,很少有大规模函数变动的情况。不过问题是,xdebug并没有提供函数覆盖的接口。

于是,我们现在碰到的场景是:

【1】希望测到某次测试中所覆盖的所有函数列表,知道这个项目总共有多少个函数,计算一下覆盖率是否足够高。

【2】测试完成之后,要生成一份覆盖率报告,将代码的覆盖情况可视化。

【3】完整测试的流程如下:

澳门新浦京手机版 1

其中插桩的意思是在测试执行之前的一些准备工作。

很多PHP程序员调试使用echo、print_r等,其实对
于有较丰富开发经验的程序员来说这些也已经足够了,他们往往可以在程序执行的过程中,通过输出特定变量的值可以判断程序执行是否正确,甚至效率高低也可以
看出来。那么我们为什么还需要一个专门的调试程序来监控我们的程序运行呢?
这个问题的答案不妨留到后面来揭晓。

 

3. 函数覆盖率解决方案

(1)原理

xdebug天生提供了对行覆盖率的支持,我们要自己计算出函数覆盖率。函数覆盖率需要两点数据,一个是哪些函数被执行,一个是文件中总共有多少个函数。

文件中总共的函数量,由于我们不可能把所有函数都执行一遍,因此这部分只能通过代码静态扫描来实现。如果是在C++或者Java中,可能就需要词法分析工具了,然而在最美的语言PHP面前,我们完全不需要那么复杂。从PHP4.3开始,PHP
Zend
Engine中内置了tokenizer功能,帮助开发者做源码词法分析。我们只需要找到PHP中定义函数时所对应的词法规律,就可以轻松得到指定PHP文件中的全部函数了。

tokenizer定义的接口也十分简单:

array token_get_all (string $source)

该函数进行文件解析,将php源代码拆成由token组成的数组。

string token_name (int $token)

将整数形式的token转变为字符串形式。类似于C语言中的strerror函数。有了tokenizer,自己再根据php函数定义的规律和格式设计一个有限状态机,即可完成全量函数的解析。这部分代码,本人写了个比较简陋的,把它单独拿出来,仅供大家参考:PHPFunctionParser

求函数覆盖率的另外一个难点在于获取被执行的函数列表。这地方让我们走了一些弯路。一开始一个最简单的办法,我们既然通过xdebug拿到被执的行,可以通过行号来反推此行属于哪一个函数。然而每一次的请求获取的行号信息量是非常大的,如果一个求情执行了1000行,那就要进行1000次判断,效率上会比较差。调研了一番之后,发现xdebug提供了function
trace的功能,可以把一次请求中的函数调用关系获取到,只不过拿到了函数名字,却没办法得到它所在的文件。于是,再次调研一番,发现了Reflection,给定方法名和类名,可以反推出来它在哪个文件中定义。于是我们使用function
trace把函数调用关系暂存在一个临时文件中,然后通过文件解析,拿到执行的函数名(如果是类方法,则是“类名::函数名”的形式),再通过reflection机制反推出定义这个函数的文件即可。再次体会到了世界上最美语言的强大之处。

(2)插桩

为了降低使用门槛,我们尽可能少地改变PHP源代码为好。xdebug收集信息的原理是分别调用xdebug_start_code_coverage和xdebug_stop_code_coverage来控制覆盖率信息收集的开始和结束,因此不可避免地要改变源代码。此处我们的解决办法是,将xdebug_stop_code_coverage通过register_shutdown_function注册为php程序结束前必须要跑的一段程序(类似C语言的atexit函数),将其封装到一个文件中,然后在源代码第一行require这个文件即可。如果你的PHP框架是CodeIgniter这种所有请求都有一个统一入口index.php的框架,那就只需要改变这一个文件即可,对源代码只有一行的改动!实际上,目前基本上所有的PHP框架,都是以一个index.php文件作为所有请求的入口。

我们对源代码的改动只有入口文件index.php的第一行加入了一句话:

require_once "/file/path/to/phpcoverage.php"; ?>

而phpcoverage.php核心代码逻辑大致如下:

<?php
 ……
function xdebugPhpcoverageBeforeShutdown(){
 ……
 $lineCovData = xdebug_get_code_coverage();
 xdebug_stop_code_coverage();
 ……
 xdebug_stop_trace();
 ……
}
register_shutdown_function(‘xdebugPhpcoverageBeforeShutdown’);
……
xdebug_start_trace(……);
xdebug_start_code_coverage();
//备注:上面省略号表示非关键代码,这里就不展示了

(3)信息存储

我们的函数覆盖率测试有了思路,使用xdebug的function
trace获取一次请求中所有函数的调用关系,得到执行过的所有函数,输出到文件中,通过文件解析和reflection获得被执行的函数名和该函数所在文件。将这些信息存入数据库或文件即可。

之前试用Spike的时候,我们发现这些信息以xml格式存入文件,数据冗余度很高,导致几个测试下来,文件已经非常大了。这显然不是我们想看到的。因此在数据存储的时候,我们直接将数据做json格式的序列化,字符串形式存在文件中,大大减少了文件大小。与此同时,我们再通过请求来源的IP和日期作为分隔,分别存储不同的文件。这样,来自每个机器每天的请求数据都能一目了然,向着“精准”的方向又迈进了一步,可以对测试人员的每个请求做精确的监控。下图是我们在业务实践中搜集的部分数据文件截图:

澳门新浦京手机版 2

这样,来自任何一个IP的每一次Web请求,它所覆盖的行和函数信息,都会被记录到文件中。对于一般的项目测试中,也就只有几个测试人员在使用,所以不需要考虑一些性能问题。

二、什么是Xdebug?

<!–[if !supportLists]–>一、<!–[endif]–>安装篇(XDebug 和PHPUnit)

4. 报告生成

上面讲了生成覆盖率数据的原理,不过我们至此获得的只是一份份的数据文件,如何汇总成一份完整的报告呢?这就需要我们自己来写一段脚本解析刚才生成的数据文件了。我们的做法是借鉴了开源工具spike
phpcoverage的模版,并加入自己的代码逻辑,特别是加入了该工具所不具有的函数覆盖率统计数据。我们自己测试的web页面生成的报告如下:

澳门新浦京手机版 3

图中可以看到每个文件的行覆盖率,函数覆盖率,还有总的覆盖率统计数据。如果需要更精确的数据,可以点进文件连接,查看到底覆盖的是哪些代码行(蓝色为覆盖,红色为未覆盖):

澳门新浦京手机版 4

Xdebug是一个开放源代码的PHP程序调试器,可以用来跟踪,调试和分析PHP程序的运行状况。

A:安装XDebug:

5. 总结

业务测试中做Web测试时,对代码的覆盖率是衡量测试质量的重要指标。我们希望通过此方法做到尽量地“精准”,测试执行完后可以精确看到哪一行代码被执行过,哪一行没被执行过。分析没被执行过的原因,从而改进测试用例。使用工具的流程也很简单,插桩=>测试=>搜集数据=>出报告。并且此解决方案最大化地减少了对业务代码的影响,只需要改一行代码即可。即便中间出现了问题,也可以快速将代码恢复为原来的样子。让测试放心,让开发也放心。

不过,最后还需要强调的一点是,并不是说覆盖了所有的代码,就证明测试已经完整了。只不过没被覆盖的话,一定是不完整的。所以这个方案最大的意义在于能够发现测试中一些遗漏的代码,找到一部分问题。其实,它也可以帮助新来的员工理解整个项目代码结构,我们可以清晰的知道,自己的每一次浏览器请求,到底在运行服务器上的哪些代码。

三、Windows 下 XDebug 安装与配置

Xdebug网下载xdebug  dll文件,存放到php加载的ext目录下(可以选择重命名,比如php_xdebug.dll,然后打开php.ini文件,添加配置

  1. 下载XDebug二进制文件:
    代码如下:5.2

    . 找到并打开
    php.ini 文件3. 如果配置过 ZendOptimizer, 需要先屏蔽 ZendOptimizer
    有关的配置, 通常如下:复制代码
    代码如下:[Zend]zend_extension_manager.optimizer_ts=”pathZendOptimizer-3.3.0libOptimizer-3.3.0″zend_extension_ts=”pathZendOptimizer-3.3.0libZendExtensionManager.dll”将其删除或用分号注释掉,如改为:复制代码
    代码如下:;[Zend];zend_extension_manager.optimizer_ts=”pathZendOptimizer-3.3.0libOptimizer-3.3.0″;zend_extension_ts=”pathZendOptimizer-3.3.0libZendExtensionManager.dll”4.
    加入 XDebug 配置。参考如下:复制代码
    代码如下:[Xdebug]zend_extension_ts=”path/xdebug/php_xdebug-2.1.2-5.2-vc6.dll”xdebug.auto_trace=onxdebug.trace_output_dir=”pathxdebug”xdebug.profiler_enable=onxdebug.profiler_output_dir=”pathxdebug”xdebug.collect_params=onxdebug.collect_return=onxdebug.remote_enable=onxdebug.remote_handler=dbgpxdebug.remote_host=localhostxdebug.remote_port=9000

[xdebug]

说明:上面 “path” 的地方需要修改为你自己的本地路径.参数解释:复制代码
代码如下:zend_extension_ts=”c:/webserver/php5/ext/php_xdebug.dll”;加载xdebug模块。这里不能用extension=php_xdebug.dll的方式加载,必须要以zend的方式加载,否则安装上后,phpinfo是显示不出xdebug这个项的。xdebug.auto_trace=on;;自动打开“监测函数调用过程”的功模。该功能可以在你指定的目录中将函数调用的监测信息以文件的形式输出。此配置项的默认值为off。xdebug.collect_params=on;;打开收集“函数参数”的功能。将函数调用的参数值列入函数过程调用的监测信息中。此配置项的默认值为off。xdebug.collect_return=on;打开收集“函数返回值”的功能。将函数的返回值列入函数过程调用的监测信息中。此配置项的默认值为off。xdebug.trace_output_dir=;设定函数调用监测信息的输出文件的路径。xdebug.profiler_enable=on;打开效能监测器。xdebug.profiler_output_dir=;设定效能监测信息输出文件的路径。

   zend_extension_ts =
php_xdebug.dll

还有一些更为具体的参数设定,详见:.
重启web服务器,如 Apache 或者 IIS6. 查看 phpinfo 的输出, 如果看到 XDebug
的选项, 就说明配置成功了.7.
调试信息文件查看。在本地运行php程序,会在所设定的目录里产生一些调试信息的文件,主要包括:a.
函数调用过程监测信息文件,文件名格式:trace.××××××.xt。该文件可直接查看,里面包含了函数运行的时间,函数调用的参数值,返回值,所在的文件和位置等信息。内容格式相对直观。b.
效能监测文件,文件名格式:cachegrind.out.××××××××。该文件也可以直接查看,但信息格式不易被人类所理解,我们可以安装
wincachegrind 软件,以格式化地读取它。
下载安装方法参考如下:下载:
working folder(php.ini里 xdebug.profiler_output_dir
的值)这样就可以比较直观的查看效能监测文件的信息了。

   xdebug.profiler_enable = on

四、linux下 XDebug 安装与配置

   xdebug.trace_output_dir =
D:PHPAPPXDebug

linux 下可以下载源代码编译安装,方法参考如下。1.下载对应 php
版本的源代码 source:
.
编译安装复制代码 代码如下:tar -xvzf
xdebug-2.1.2.tgzcd xdebug-2.1.2./configuremakemake install如果有报错
phpize 没有这个command,那么安装它:复制代码 代码如下:sudo apt-get install
php5-dev3. 将xdebug.so文件移到php5下面复制代码 代码如下:cp modules/xdebug.so
/usr/lib/php5/4. 编辑php.ini,加入下面几行:复制代码 代码如下:[Xdebug]zend_extension=
/usr/lib/php5/xdebug.soxdebug.profiler_enable=onxdebug.trace_output_dir=”../xdebug”xdebug.profiler_output_dir=”../xdebug”

  
xdebug.profiler_output_dir=D:PHPAPPXDebug

5. 重启Apache,测试是否安装成功

 

如果输出的内容中有看到xdebug,说明安装配置成功。

xdebug需要采用zend引擎加载的方式加载,所以用zend_extension_ts或是zend_extension,  ts是thread_safety, 目前5.3以上才支持zend_extension加载,<5.3的用zend_extension_ts加载(或者你可以查看phpinfo是否启用了zts),然后重启apache,查看phpinfo,就发现XDebug选项了。

澳门新浦京手机版 5

可以看到xdebug.profiler_enable,xdebug.profiler_output_dir,xdebug.trace_output_dir这三个是我们刚刚配置的项,可以安装自己的需要配置剩余项,xdebug.profiler_enable:开启性能分析,

开启这个之后会在xdebug.profiler_output_dir这个目录下生成cachegrind.out.XXX的分析文件,如果指定了xdebug.profiler_output_name这个,则输出来的文件就会是指定的名字.xxx的格式(此方法不适合分析,原因稍后说明),

xdebug.trace_options:这个是开启跟踪项,

     开启该项之后,会在xdebug.trace_output_dir下生产跟踪文件,注意该项会影响运行速度,因为他需要记录跟踪过程中的一系列事件。**

      关于XDebug还有一点需要注意的:XDebug是调试的,也就是说配置了XDebug那程序运行的就是一个Debug状态,所以这时候zend_optimizer就不能用了,总不能让程序即调试状态又处于优化状态哈。**

     更多关于XDebug的,大家去网上发掘吧~~然后一起探讨哈

友情提醒:对于使用集成环境的同学,比如Wamp,它拥有两个PHP.ini配置文件,一个在Apache下,一个在PHP下,Apache下是影响web的,而PHP下是影响命令行的,所以····(感谢俊哥的提醒)


 

B:安装PHPUnit:

关于PHPUnit的安装过程,网上也已经很多了,之前自己为了终于安装成功之后也小写了篇安装篇(

PHPUnit安装用的是pear的安装方式,所以如果机子没有安装过pear包需要先安装下,一般在php安装的时候在其安装目录下都有一个go-pear.bat文件,直接执行即可完成安装,【这里安装需要注意扩展exif,这个扩展会用到mbstring扩展中的方法,所以mbstring的加载顺序需要再exif之上。】完成pear的安装之后就可以执行pear,查看pear的命令参数,

澳门新浦京手机版 6

然后依次执行:

pear channel-discover
pear.phpunit.de   

pear install –alldeps
phpunit/PHPUnit

需要注意的是现在最新版的phpunit是3.5的··但是这个只有pear的版本是1.6以上及PHP5.2.X才会安装得到最新版·否则是安装的是第一次的版本(不过不影响使用)。

安装好后就可以执行phpunit查看相关信息:

澳门新浦京手机版 7

可以看到有—coverage-html –coverage-clover
–coverage-source这三个选项·就是因为在XDebug安装成功之后才能用,这三个对于导出覆盖率文件可是很重要的选项。

 

<!–[if !supportLists]–>二、<!–[endif]–>PHPUnit 单元测试覆盖率分析

单元测试,最重要的指标之一就是覆盖率。这点虽然Zend Studio上可以很清晰的看出来,可是要导出成一分文档就不太好使了,所以这时候XDebug就又可以帮上忙了,使用的时候也挺简单,调用命令即可:

phpunit –coverage-html
D:PHPAPPXDebug  YouTest

这样就会将生成的覆盖文件(html格式的)放在D:PHPAPPXDebug目录下了,

澳门新浦京手机版 8

然后就可以在放置的目录下找到一堆的html文件,运行下index.html

澳门新浦京手机版 9

就可以看到这样的图了,英文字母很简单··意思也明了就不解释了,说明一点:

测试结果说明:一共有5种,上图的例子出现了两种。

   .  
:代表正确

   F   
:代表断言错误

   E  
:代表PHP程序错误或是异常

   I   
: 代表没有实现的方法

   S  
:  代表是跳过的方法

生产的覆盖文件说明:

Classes: 只有一个类中的所有方法都被覆盖的时候,这个类才算是被测试完的

Functions/Methods
:只有一个方法或是函数的所有有效的语句代码都被执行到了才算这个方法或是函数是被测试完的

Lines:   总行数将会不饱行注释,空行,<?php ?> 标签, 及类及方法的声明。

使用phpunit –coverage-clover
D:PHPAPPXDebugfirst.xml 
YouTest

生产的将会是一个xml格式的文件,这个格式的文件效果不明显,没有html格式的好,这边的效果被我删掉了所以么有效果图可看,第三个覆盖文件的参数我没测试过,大家有兴趣可以试试。

 

<!–[if !supportLists]–>三、<!–[endif]–>程序执行性能分析

XDebug除了有效的帮助分析单元测试覆盖率之外,还可以帮组分析程序执行的瓶颈所在,开启分析的功能:

xdebug.profiler_enable = on

 xdebug.profiler_output_dir=D:PHPAPPXDebug

设置上面两项,然后执行你要分析的程序,就会在上面的目录下看到cachegrind.out.XXX的文件,这个文件直接打开就是一些记录,需要借助第三方的cachegrind查看工具才行,一个好用的工具是winCacheGrind,查看起来很方便。

澳门新浦京手机版 10

可以看到执行的总时间,及每个函数执行的时间。

因为这个工具在打开文件的时候,只能打开cachegrind.out.*的文件,所以待分析的文件必须是这个名字的,所以为了省去重命名,这也就是为啥我说不建议修改xdebug.profiler_output_name这个选项的原因。

 

<!–[if !supportLists]–>四、<!–[endif]–>XDebug库函数

XDebug除了上述方式外,还有自己的一些函数库提供,可以在你程序的代码段任何地方执行,具体的请看

 

XDebug的功能,还不止这些,因为他的选项·好大的一页,所以还是去这里看看官方的说明。靠谱!

发表评论

电子邮件地址不会被公开。 必填项已用*标注