PHP代码覆盖率统计详解


Posted in PHP onJuly 22, 2020

一 安装php环境

二 统计php代码覆盖率

1 需要安装xdebug

安装步骤:

测试环境

  • LNMP 军哥一键包1.3版本
  • PHP 7.0.7
  • Xdebug 2.6

配置步骤

git clone git://github.com/xdebug/xdebug.git
cd xdebug
find / -name phpize
/usr/bin/phpize
find / -name php-config
./configure --enable-xdebug --with-php-config=/usr/local/php/bin/php-config
make
make install

开启扩展

find / -name php.ini
vi /usr/local/php/etc/php.ini
添加 extension=xdebug.so
[Xdebug]
xdebug.collect_params=on
xdebug.collect_return=on
xdebug.remote_autostart=on

service restart php-fpm

成功验证:①在linux输入php -version,如下:

PHP代码覆盖率统计详解

②访问index.php(phpinfo())

PHP代码覆盖率统计详解

2 安装composer

curl -sS https://getcomposer.org/installer | php
php composer.phar --version
Composer version 1.6.5 2018-05-04 11:44:59

3 安装phpcov 和 phpunit

此处选了phpunit 6.5.0 和phpcov 4.0.8,编辑composer.json文件(phpcov是根据phpunit自动匹配的,php和phpunit对应关系可百度或看底部)

#composer.json
{
 "name": "root/php-code-coverage",
 "require-dev": {
 "phpunit/phpunit":"6.5.0",
 "phpunit/phpcov": "*"
}

执行命令安装 php composer.phar install

安装完成后校验 如下即可(phpunit和phpcov一定要在这个目录下使用)

vendor/bin
[root@mt-jry-01 bin]# ll
lrwxrwxrwx 1 root root 24 Jul 13 10:22 phpcov -> ../phpunit/phpcov/phpcov
lrwxrwxrwx 1 root root 26 Jul 13 10:21 phpunit -> ../phpunit/phpunit/phpunit
[root@mt-jry-01 bin]# .vendor/bin/phpunit --version
PHPUnit 6.5.0 by Sebastian Bergmann and contributors.
 
[root@mt-jry-01 bin]# .vendor/bin/phpcov --version
phpcov 4.0.5 by Sebastian Bergmann.

4 编写测试代码

#userinfo.php
<?php
include_once("*****/prepend.php"); 
$id = $_POST["user_id"];
if ($id != 10086){
 exit();
}
$userinfo = array(
 'username'=>'jason',
 'password'=>'123456',
);
$result = array(
  'code'=>10000,
  'message'=>"success",
  'data'=>$userinfo,
 );
echo json_encode($result);
#prepend.php
<?php
require_once dirname(__FILE__).'/vendor/autoload.php'; # 在composer生成的vender同级目录
use SebastianBergmann\CodeCoverage\CodeCoverage;
$coverage = new CodeCoverage;
 
$coverage->filter()->addDirectoryToWhitelist('/var/www/html/userinfo.php'); # 白名单<br>$coverage->filter()->removeDirectoryFromWhitelist('/var/www/html/userinfo.php'); # 从白名单中移除文件夹<br>$coverage->filter()->removeFileFromWhitelist('/var/www/html/userinfo.php'); # 从白名单中移除文件
$coverage->start('<Site coverage>');#开始统计
register_shutdown_function('__coverage_stop',$coverage);#注册关闭方法
 
function __coverage_stop(CodeCoverage $coverage){
 $coverage->stop();#停止统计
 $cov = '<?php return unserialize(' . var_export(serialize($coverage), true) . ');';#获取覆盖结果,注意使用了反序列化
 //echo $cov;
 file_put_contents(dirname(__FILE__).'/cov/site.' . date('U') .'.'.uniqid(). '.cov', $cov);#将结果写入到文件中
}
 
若多个域名或者接口请求要在同一个prepend文件里分别统计,在新建$coverage前加if条件即可,如
if(strpos($_SERVER['HTTP_HOST'],'www.baidu.com') === true){}

5 测试

执行命令

[root@mt-jry-01 html]# curl -d "user_id=10086" "127.0.0.1/userinfo.php"
{"code":10000,"message":"success","data":{"username":"jason","password":"123456"}}

查看prepend.php统计目录cov下

-rw-r--r-- 1 apache apache 4609 Jul 13 14:45 site.1531464305.5b484a71c0a1c.cov

生成xml或者html报告命令如下:

./vendor/bin/phpcov merge --clover cov/coverage.xml cov/ -vvv # 在cov目录下生成xml报告
./vendor/bin/phpcov merge --html="cov/coverage_html" cov/ -vvv # 在cov目录下生成html报告 

6 查看报告结果

PHP代码覆盖率统计详解

8 工程配置

在实际项目中有三种配置方式

  1. 在php.ini中引入prepend文件:auto_prepend_file = /***/prepend.php (配置后重启php) --- 所有php请求均会预加载该文件,文件有错误时影响整个php服务
  2. 在文件入口文件中引入prepend文件:include_once(/www/***/prepend.conf); (一般为index.php) --- 效果同3,重新部署清掉配置
  3. 在nginx.conf中引入prepend文件 --- 对于该域名的请求会加载该文件(配置后重启nginx)
location ~ .*\.php?$
{ 
 fastcgi_pass 127.0.0.1:9200;
 fastcgi_index index.php;
 include common/fastcgi.conf;
 fastcgi_param MY_ENV pre;
 fastcgi_param PHP_VALUE 'auto_prepend_file=/www/data/phpcoverage/prepend.php';
}
 

7 问题:

① 开始使用的phpcov 2.0.2 & phpunit 4.8.7 生成的报告数据全为0 - phpunit4 不能支持 php7,对应版本见⑦

② 开始总是报错PHP Fatal error: Uncaught Error: Class 'SebastianBergmann\CodeCoverage\CodeCoverage' not found in

是因为没有引用vender目录,在prepend.php里加一句require_once dirname(__FILE__).'/vendor/autoload.php'; 即可

③ 配置nginx

④ 请求域名没有生成site文件:请求权限不够,不能在对应目录下写文件

chmod 777 -R 域名请求是apache权限,如果与cov文件夹权限不一致则不可写入

⑤ 生成覆盖率文件有要统计的代码文件,但是命中情况count全为0,有两种可能

A xdebug的collect_param 与collect_return没打开,导致未收集到数据,需要在php.ini里配置

B 如果在php.ini里配置了auto_prepend_file=‘**/prepend.php',则只有用指定目录下的prepend.php文件才能生成覆盖率数据,否则覆盖行全为0

⑥ 将xml报告集成到jenkins

注意:go 和 c++ 的xml报告可以用 Cobertura 统计到jenkins展示,php 的要用Clover PHP 插件统计,phpcov生成的xml格式Cobertura解析不了会报错

⑦ php 和 phpunit 的对应关系https://phpunit.de/supported-versions.html

PHP代码覆盖率统计详解

⑧ 问题:观察每日构建的覆盖率,在代码未更新,用例未更新的前提下,覆盖率降低

  1. 该方式统计的代码总行数变化,与之前不一致 -- 实际两天的代码完全一致
  2. 同一个文件的覆盖行数不一致,发现会出现同一个分支中,上下行未覆盖,而中间行覆盖 和 空行被覆盖(空白行 绿色,鼠标放置提示 1test covers..)的

原因:猜测是 xdebug 统计抽风,因为 xdebug 负责收集统计代码,phpunit phpcov只是汇总整理为可读报告。

解决:暂不能解决,可观察xdebug和phpcoverage官网有类似问题

⑨ jenkins 配置

cur_path=`pwd`
echo ${cur_path}
 
# 删除历史cov文件,保证覆盖率干净
find /www/data/phpcoverage/admin_cov/ -name "site*" | xargs rm -rf
rm -rf ${cur_path}/reports/*
 
#在工程入口文件引入 prepend 文件
sed -i '2cinclude_once("/www/data/phpcoverage/prepend.php");' /www/my_project/index.php
 
# 更新自动化用例并执行用例
source /www/data/project3/venv/bin/activate
git checkout master
git pull
python run.py
 
# 统计html和xml报告,html更易读,xml更直观反映历史情况
cd /www/data/phpcoverage
./vendor/bin/phpcov merge --clover ${cur_path}/reports/coverage.xml admin_cov/ -vvv
./vendor/bin/phpcov merge --html="${cur_path}/reports/coverage_html" admin_cov/ -vvv
 
# 从入口文件删除引用
sed -i '2c//' /www/my_project/index.php

https://github.com/sebastianbergmann/phpcov

到此这篇关于PHP代码覆盖率统计详解的文章就介绍到这了,更多相关PHP代码覆盖率内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

PHP 相关文章推荐
聊天室php&amp;mysql(三)
Oct 09 PHP
mysql 中InnoDB和MyISAM的区别分析小结
Apr 15 PHP
php数组函数序列之array_pop() - 删除数组中的最后一个元素
Nov 07 PHP
php解决抢购秒杀抽奖等大流量并发入库导致的库存负数的问题
Jun 19 PHP
php使用google地图应用实例
Dec 31 PHP
PHP封装CURL扩展类实例
Jul 28 PHP
php生成gif动画的方法
Nov 05 PHP
php微信公众平台示例代码分析(二)
Dec 06 PHP
laravel5.4利用163邮箱发送邮件的步骤详解
Sep 22 PHP
PHP自定义序列化接口Serializable用法分析
Dec 29 PHP
PHP中创建和编辑Excel表格的方法
Sep 13 PHP
php实现的生成排列算法示例
Jul 25 PHP
php实现统计IP数及在线人数的示例代码
Jul 22 #PHP
Yii使用DbTarget实现日志功能的示例代码
Jul 21 #PHP
浅谈PHP之ThinkPHP框架使用详解
Jul 21 #PHP
浅谈php常用的7大框架的优缺点
Jul 20 #PHP
KindEditor在php环境下上传图片功能集成的方法示例
Jul 20 #PHP
php连接mysql之mysql_connect()与mysqli_connect()的区别
Jul 19 #PHP
PHP+MySql实现一个简单的留言板
Jul 19 #PHP
You might like
一拳超人中怪人协会钦定! S级别最强四人!
2020/03/02 日漫
法压式咖啡之制作法
2021/03/03 冲泡冲煮
PHP注释实例技巧
2008/10/03 PHP
Php中使用Select 查询语句的实例
2014/02/19 PHP
Yii不依赖Model的表单生成器用法实例
2014/12/04 PHP
PHP多态代码实例
2015/06/26 PHP
PHP基于IMAP收取邮件的方法示例
2017/08/07 PHP
php实现支持中文的文件下载功能示例
2017/08/30 PHP
ThinkPHP5+UEditor图片上传到阿里云对象存储OSS功能示例
2019/08/05 PHP
js中格式化日期时间型数据函数代码
2010/11/08 Javascript
Js中的onblur和onfocus事件应用介绍
2013/08/27 Javascript
JavaScript避免代码的重复执行经验技巧分享
2014/04/17 Javascript
html的DOM中document对象anchors集合用法实例
2015/01/21 Javascript
使用Browserify配合jQuery进行编程的超级指南
2015/07/28 Javascript
javascript数据类型验证方法
2015/12/31 Javascript
详解JS面向对象编程
2016/01/24 Javascript
基于JS实现横线提示输入验证码随验证码输入消失(js验证码的实现)
2016/10/27 Javascript
详解vue-cli 脚手架项目-package.json
2017/07/04 Javascript
vue中使用refs定位dom出现undefined的解决方法
2017/12/21 Javascript
React之PureComponent的使用作用
2018/07/10 Javascript
vue router 跳转时打开新页面的示例方法
2019/07/28 Javascript
详解React中共享组件逻辑的三种方式
2021/02/02 Javascript
Python利用递归实现文件的复制方法
2018/10/27 Python
python 调用有道api接口的方法
2019/01/03 Python
Python函数生成器原理及使用详解
2020/03/12 Python
jupyter notebook 参数传递给shell命令行实例
2020/04/10 Python
用python给csv里的数据排序的具体代码
2020/07/17 Python
Python如何给函数库增加日志功能
2020/08/04 Python
python破解同事的压缩包密码
2020/10/14 Python
HolidayLettings英国:预订最好的度假公寓、别墅和自助式住宿
2019/08/27 全球购物
俄罗斯Sportmarket体育在线商店:用于旅游和户外活动
2019/11/12 全球购物
网络安全类面试题
2015/08/01 面试题
大二法英学生职业生涯规划范文
2014/02/27 职场文书
新学期教师寄语
2014/04/02 职场文书
2014教师专业技术工作总结
2014/12/03 职场文书
python 中[0]*2与0*2的区别说明
2021/05/10 Python