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 相关文章推荐
一个简洁的多级别论坛
Oct 09 PHP
基于xcache的配置与使用详解
Jun 18 PHP
Eclipse的PHP插件PHPEclipse安装和使用
Jul 20 PHP
php中strtotime函数用法详解
Nov 15 PHP
smarty表格换行实例
Dec 15 PHP
PHP中的魔术方法总结和使用实例
May 11 PHP
反射调用private方法实践(php、java)
Dec 21 PHP
PHP网站自动化配置的实现方法(必看)
May 27 PHP
PHP实现微信提现功能
Sep 30 PHP
PHP常见加密函数用法示例【crypt与md5】
Jan 27 PHP
thinkPHP5.1框架中Request类四种调用方式示例
Aug 03 PHP
phpfpm的作用和用法
Oct 10 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
DOTA2 6.87版本后新眼位详解攻略
2020/04/20 DOTA
解析file_get_contents模仿浏览器头(user_agent)获取数据
2013/06/27 PHP
form表单传递数组数据、php脚本接收的实例
2017/02/09 PHP
thinkphp关于简单的权限判定方法
2017/04/03 PHP
javascript下判断一个元素是否存在的代码
2010/03/05 Javascript
判断目标是否是window,document,和拥有tagName的Element的代码
2010/05/31 Javascript
实用的JS正则表达式(手机号码/IP正则/邮编正则/电话等)
2013/01/11 Javascript
Array 重排序方法和操作方法的简单实例
2014/01/24 Javascript
Window.Open如何在同一个标签页打开
2014/06/20 Javascript
深入解读JavaScript中的Hoisting机制
2015/08/12 Javascript
轻松学习jQuery插件EasyUI EasyUI表单验证
2015/12/01 Javascript
浅析jquery与checkbox的checked属性的问题
2016/04/27 Javascript
JS+HTML5手机开发之滚动和惯性缓动实现方法分析
2016/06/12 Javascript
jQuery简单入门示例之用户校验demo示例
2016/07/09 Javascript
jquery select2的使用心得(推荐)
2016/12/04 Javascript
js实现关闭网页出现是否离开提示
2017/12/07 Javascript
JS实现图片居中悬浮效果
2017/12/25 Javascript
jQuery实现鼠标点击处心形漂浮的炫酷效果示例
2018/04/12 jQuery
node中modules.exports与exports导出的区别
2018/06/08 Javascript
Vue使用自定义指令实现拖拽行为实例分析
2020/06/06 Javascript
Vue中nprogress页面加载进度条的方法实现
2020/11/13 Javascript
Python基本数据类型详细介绍
2014/03/11 Python
Python 搭建Web站点之Web服务器与Web框架
2016/11/06 Python
python使用matplotlib库生成随机漫步图
2018/08/27 Python
在PyCharm中控制台输出日志分层级分颜色显示的方法
2019/07/11 Python
python 字符串追加实例
2019/07/20 Python
python实现读取类别频数数据画水平条形图案例
2020/04/24 Python
python opencv把一张图片嵌入(叠加)到另一张图片上的实现代码
2020/06/11 Python
详解Html5 Canvas画线有毛边解决方法
2018/03/01 HTML / CSS
盖尔斯工厂店:GUESS Factory
2020/01/21 全球购物
娇韵诗俄罗斯官方网站:Clarins俄罗斯
2020/10/03 全球购物
自荐信的两点禁忌
2013/10/30 职场文书
通用自荐信范文
2014/03/14 职场文书
本科毕业生求职信
2014/06/15 职场文书
旅游饭店管理专业自荐书
2014/06/28 职场文书
详细聊聊关于Mysql联合查询的那些事儿
2021/10/24 MySQL