2.22.1 PHPUnit:自动化单元测试
目前核心框架单元测试的覆盖率(高达90%以上!!!此处应该有掌声~):
注意,此测试截图并不是最新的,但我们一直都在致力坚持单元测试。这一点,你可以在单元测试的代码中找到证明。
2.22.2 Phing:一键部署、快速发布
无论如何,都应该走自动化发布流程,避免人工地打包、上传、解压、改生产配置这些重复性的人工操作。
在自动化发布中,Phing是个不错的尝试。
以下是我某个项目中的使用配置,出于对项目的保护,部分数据已删除,但仍然可以参考。
(1)发布配置 - build.xml
主要的操作有:
- 备份当前代码,并删除一天前的备份
- 从SVN签出最新的发布代码
- 执行配置检测脚本
- 代码发布切换,并替换使用线上配置文件
- 移除单元测试初始化文件,以免误执行
<?xml version="1.0" encoding="UTF-8"?>
- 移除单元测试初始化文件,以免误执行
<!— ============================================ —>
<!— PhalApi —>
<!— @dogstar 20141221 —>
<!— ============================================ —>
<project name="demo.phalapi.com" default="build">
<property
name="backup_path"
value="/home/apps/backup/demo.phalapi.com"
override="true" />
<property
name="backup_prefix"
value="demo.phalapi.com_phing_backup_"
override="true" />
<property
name="svn_todir"
value="/home/apps/svn/demo.phalapi.com"
override="true" />
<!-- ============================================ -->
<!-- Target: prepare -->
<!-- ============================================ -->
<target name="prepare">
<mkdir dir="./Runtime" />
<mkdir dir="${svn_todir}" />
<mkdir dir="${backup_path}" />
</target>
<!-- ============================================ -->
<!-- Target: svn checkout -->
<!-- ============================================ -->
<target name="svncheckout">
<svncheckout
repositoryurl="svn://127.0.0.1/PhalApi/demo/release"
username="test"
password="123456"
nocache="true"
todir="${svn_todir}" />
</target>
<!-- ============================================ -->
<!-- Target: svn update -->
<!-- ============================================ -->
<target name="svnup" depends="svncheckout">
<svnupdate
repositoryurl="svn://127.0.0.1/PhalApi/demo/release"
username="test"
password="123456"
nocache="true"
todir="${svn_todir}" />
</target>
<!-- ============================================ -->
<!-- Target: check config -->
<!-- ============================================ -->
<target name="checkconfig">
<php expression="include('${svn_todir}/Tools/check_config.php')" />
<php
function="checkProd"
class="Tools_Check_Config"
returnProperty="checkProdErrorMsg" />
<fail msg="${checkProdErrorMsg}" if="checkProdErrorMsg" />
</target>
<!-- ============================================ -->
<!-- Target: backup -->
<!-- ============================================ -->
<target name="backup">
<php
expression="date('Ymd', strtotime('-1 day'))"
returnProperty="backup_version_yesterday" />
<php
expression="date('Ymd')"
returnProperty="backup_version_today" />
<delete>
<fileset dir="${backup_path}">
<exclude name="${backup_prefix}${backup_version_yesterday}*" />
<exclude name="${backup_prefix}${backup_version_today}*" />
</fileset>
</delete>
<php
expression="date('YmdHis')"
returnProperty="backup_version" />
<zip destfile="${backup_path}/${backup_prefix}${backup_version}.zip" basedir="." >
<fileset dir=".">
<include name="**/**" />
<exclude name="./Runtime" />
<exclude name="./Runtime/**" />
<exclude name="./.svn" />
<exclude name="./.svn/**" />
</fileset>
</zip>
<copy
file="${backup_path}/${backup_prefix}${backup_version}.zip"
tofile="${backup_path}/${backup_prefix}lastest.zip"
overwrite="true" />
</target>
<!-- ============================================ -->
<!-- Target: build -->
<!-- ============================================ -->
<target name="build" depends="prepare,svnup,checkconfig,backup">
<copy todir="." overwrite="true" >
<fileset dir="${svn_todir}">
<include name="**/**" />
<exclude name="${svn_todir}/Config/dbs.php" />
<exclude name="${svn_todir}/Config/sys.php" />
<exclude name="${svn_todir}/Test" />
<exclude name="${svn_todir}/Test/**" />
</fileset>
</copy>
<copy
file="./Config/dbs.php.prod"
tofile="./Config/dbs.php"
overwrite="true" />
<copy
file="./Config/sys.php.prod"
tofile="./Config/sys.php"
overwrite="true" />
<!-- 避免在生产环境执行PHPUnit,故把测试环境的初始文件移开 -->
<move
file="./Test/test_env.php"
tofile="./Test/test_env.php.bak"
overwrite="true"/>
</target>
</project>
(2)回滚配置 - rollback.xml
主要操作:
- 回滚到上一个版本
<?xml version="1.0" encoding="UTF-8"?>
- 回滚到上一个版本
<!— ============================================ —>
<!— PhalApi —>
<!— @dogstar 20141222 冬至 —>
<!— ============================================ —>
<project name="demo.phalapi.com" default="rollback">
<property
name="backup_path"
value="/home/apps/backup/demo.phalapi.com"
override="true" />
<property
name="backup_prefix"
value="demo.phalapi.com_phing_backup_"
override="true" />
<property
name="svn_todir"
value="./__svn__"
override="true" />
<!-- ============================================ -->
<!-- Target: rollback -->
<!-- ============================================ -->
<target name="rollback" >
<unzip file="${backup_path}/${backup_prefix}lastest.zip" todir="." >
<fileset dir=".">
<include name="*.zip"/>
</fileset>
</unzip>
</target>
</project>
2.22.3 autobench:接口压力测试与可视化图表
可以通过以下的脚本来进行,使用示例:
$ ./autobench.sh
Usage: ./autobench.sh <host> <uri>
- ./autobench.sh www.baidu.com /index.php
参数可以自行调整。
(1)利用bench2graph生成可视化图表
纯PHP访问 - 入口欢迎接口
mysql访问 - 事件获取接口
带MC缓存的访问 - 应用入口 - 带缓存的身份token验证
(2)详细的数据报表
dem_req_rate req_rate_demo.phalapi.com con_rate_demo.phalapi.com min_rep_rate_demo.phalapi.com avg_rep_rate_demo.phalapi.com max_rep_rate_demo.phalapi.com stddev_rep_rate_demo.phalapi.com resp_time_demo.phalapi.com net_io_demo.phalapi.com errors_demo.phalapi.com
5 5.0 5.0 4.8 5.0 5.2 0.1 22.4 2.9 0
25 25.0 25.0 25.0 25.0 25.0 0.0 21.6 14.3 0
45 45.0 45.0 45.0 45.0 45.0 0.0 22.3 25.7 0
65 64.9 64.9 64.7 64.7 64.7 0.0 25.4 37.0 0
85 84.8 84.8 84.6 84.6 84.6 0.0 28.6 48.3 0
105 104.6 104.6 0.0 0.0 0.0 0.0 34.4 59.7 0
125 124.0 124.0 0.0 0.0 0.0 0.0 42.2 70.7 0
145 143.8 143.8 0.0 0.0 0.0 0.0 59.2 82.0 0
165 147.4 147.4 0.0 0.0 0.0 0.0 262.9 84.1 0
185 151.1 151.1 0.0 0.0 0.0 0.0 429.7 86.2 0
(3)附脚本
#!/bin/bash
if [ $# -eq 0 ]; then
echo "Usage: $0 <host> <uri>"
echo ""
echo " - $0 www.baidu.com /index.php"
echo ""
exit
fi
DM=$1
URL=$2
#--signle_host 只测单机
#--host1 测试主机地址
#--uri1 host1 测试URI
#--quiet 安静模式
#--low_rate 测试时最低请求数(指 httperf)
#--hight_rate 测试时最高请求数
#--rate_step 每次测试请求数增加步长
#--num-call 每连接中发起联接数,一般是1
#--num_conn 测试联接数
#--file 测试结果输出的 tsv文件
autobench \
--single_host \
--host1=$DM \
--port1=80 \
--uri1=$URL \
--low_rate=5 \
--high_rate=200 \
--rate_step=20 \
--num_call=1 \
--num_conn=500 \
--timeout=10 \
--file ./$DM.tsv
2.22.4 xhprof:性能分析工具
xhprof是一个不错的内部性能分析工具,这里不过多的讲述此工具的特点和使用,但会以对PhalApi进行的一个性能测试展示它的分析效果。
(1)测试的接口服务
http://api.phalapi.com /demo/?service=Default.Index&username=test
(2)Overall Summary
Total Incl. Wall Time (microsec): 7,873 microsecs
Total Incl. CPU (microsecs): 7,999 microsecs
Total Incl. MemUse (bytes): 304,456 bytes
Total Incl. PeakMemUse (bytes): 306,616 bytes
Number of Function Calls: 338
(3)Top 10耗时
Function Name | Calls | Calls% | Incl. Wall Time(microsec) | IWall%(microsec) | Excl. Wall Time | EWall% |
---|---|---|---|---|---|---|
PhalApi_Loader::loadClass | 10 | 3.00% | 3,020 | 38.40% | 1,038 | 13.20% |
PhalApi_Loader::loadClass1 | 4 | 1.20% | 785 | 10.00% | 398 | 5.10% |
run_init::Public/init.php | 1 | 0.30% | 3,915 | 49.70% | 327 | 4.20% |
file_exists | 18 | 5.30% | 249 | 3.20% | 249 | 3.20% |
main() | 1 | 0.30% | 7,873 | 100.00% | 248 | 3.20% |
load::zh_cn/common.php | 2 | 0.60% | 237 | 3.00% | 237 | 3.00% |
PhalApi_Loader::load | 9 | 2.70% | 3,380 | 42.90% | 226 | 2.90% |
PhalApi_DI::get | 9 | 2.70% | 1,268 | 16.10% | 223 | 2.80% |
PhalApi_Translator::addMessage | 2 | 0.60% | 522 | 6.60% | 136 | 1.70% |
DI | 15 | 4.40% | 645 | 8.20% | 134 | 1.70% |
class_exists | 11 | 3.30% | 1,383 | 17.60% | 130 | 1.70% |
load::Config/sys.php | 1 | 0.30% | 120 | 1.50% | 120 | 1.50% |
对应的图表如下:从中可以看出,主要的耗时途径在于文件的加载,下面将进一步探讨。
(4)Top 1耗时深入
所加载的文件如下:
2.22.5 Jenkis和Sonar:持续集成和静态代码分析
PhalApi从来不会隐藏自己的设计,当然,我们也不会隐藏我们内部的各个细节以及存在的问题。但和其他隐藏了技术债务的框架相比,PhalApi敢于展示自己的静态代码分析报告,并且它也是做得相当出色的。
以下截图来自 GIT@OSC 上的静态代码分析:
当你的项目很重要时,也可以使用Jenkis或者Sonar进行静态代码的分析。不要个人主观地觉得你的代码风格写得好,而是交由专业的分析工具进行解剖,并理解各个数据报表背后的含义,然后改进之。
2.22.6 Git/SVN:更多的版本控制
2.22.7 WIKI:团队沟通与文档交流
(1)markdown接口模板
#3.2 接口文档模板
##1、功能说明
_请在这里放置简短的接口功能说明。_
##2、接口URL
/?service= _接口服务名称_ + 公共参数(是否免登录态?)
##3、接口参数 [跳转](http://demo.phalapi.com/demo/checkApiParams.php?service=)
参数|必须|默认值|说明
---|---|---|---
user_id|1||用户id
##4、返回结果
###返回字段
参数|类型|说明
---|---|---
data.username|string|用户名
###结果示例
{
"ret": 200,
"data": {
.... //更多结果的说明
"msg": ""
},
"msg": ""
}
###请求示例
_请放置一个接口请求的链接。_
http://demo.phalapi.com/demo/?service=
2.22.8 静态代码分析工具 - phpmetrics
以下是针对本框架核心代码所做的分析报告:
PS:从报告的评估可以看出,我们的框架明显具有相当 高的可维护性。