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 相关文章推荐
第八节 访问方式 [8]
Oct 09 PHP
一段php加密解密的代码
Oct 09 PHP
谈谈PHP语法(4)
Oct 09 PHP
php zlib压缩和解压缩swf文件的代码
Dec 30 PHP
php入门教程 精简版
Dec 13 PHP
php循环检测目录是否存在并创建(循环创建目录)
Jan 06 PHP
PHP最常用的2种设计模式工厂模式和单例模式介绍
Aug 14 PHP
php使用file函数、fseek函数读取大文件效率对比分析
Nov 04 PHP
php中10个不同等级压缩优化图片操作示例
Nov 14 PHP
Laravel中unique和exists验证规则的优化详解
Jan 28 PHP
Laravel中的chunk组块结果集处理与注意问题
Aug 15 PHP
Ubuntu 16.04中Laravel5.4升级到5.6的步骤
Dec 07 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
php目录遍历函数opendir用法实例
2014/11/20 PHP
php隐藏IP地址后两位显示为星号的方法
2014/11/21 PHP
php实现Mongodb自定义方式生成自增ID的方法
2015/03/23 PHP
php实现支持中文的文件下载功能示例
2017/08/30 PHP
Ext对基本类型的扩展 ext,extjs,format
2010/12/25 Javascript
js中根据字数截取字符串,不能截断url
2012/01/12 Javascript
了不起的node.js读书笔记之node的学习总结
2014/12/22 Javascript
简单分析javascript面向对象与原型
2015/05/21 Javascript
Javascript仿新浪游戏频道鼠标悬停显示子菜单效果
2015/08/21 Javascript
详解Nodejs之静态资源处理
2017/06/05 NodeJs
JavaScript获取移动设备型号的实现代码(JS获取手机型号和系统)
2018/03/10 Javascript
vue项目中使用百度地图的方法
2018/06/08 Javascript
微信小程序分享功能之按钮button 边框隐藏和点击隐藏
2018/06/14 Javascript
送你43道JS面试题(收藏)
2019/06/17 Javascript
jQuery 选择器用法基础入门示例
2020/01/04 jQuery
ES6函数实现排它两种写法解析
2020/05/13 Javascript
python调用百度语音识别api
2018/08/30 Python
利用Python实现原创工具的Logo与Help
2018/12/03 Python
对python 通过ssh访问数据库的实例详解
2019/02/19 Python
Python中asyncio模块的深入讲解
2019/06/10 Python
正则给header的冒号两边参数添加单引号(Python请求用)
2019/08/09 Python
浅谈pycharm使用及设置方法
2019/09/09 Python
Python编程快速上手——强口令检测算法案例分析
2020/02/29 Python
Python实现网络聊天室的示例代码(支持多人聊天与私聊)
2021/01/27 Python
中国网上药店领导者:1药网
2017/02/16 全球购物
Oroton中国官网:澳洲知名奢侈配饰品牌
2017/03/26 全球购物
Hunkemöller西班牙:欧洲最大的内衣连锁店
2018/08/15 全球购物
联想阿根廷官方网站:Lenovo Argentina
2019/10/14 全球购物
公司业务主管岗位职责
2013/12/07 职场文书
采购经理岗位职责
2014/02/16 职场文书
幼儿园毕业寄语
2014/04/03 职场文书
班主任工作经验交流材料
2014/05/13 职场文书
纪检干部先进事迹材料
2014/08/23 职场文书
Go使用协程交替打印字符
2021/04/29 Golang
SpringBoot集成Redis的思路详解
2021/10/16 Redis
Springboot/Springcloud项目集成redis进行存取的过程解析
2021/12/04 Redis