##2.22.1 PHPUnit:自动化单元测试
目前核心框架单元测试的覆盖率(高达90%以上!!!此处应该有掌声~):
![a pic](http://webtools.qiniudn.com/131634_NHlk_256338.jpg)
注意,此测试截图并不是最新的,但我们一直都在致力坚持单元测试。
这一点,你可以在单元测试的代码中找到证明。
##2.22.2 Phing:一键部署、快速发布
无论如何,都应该走自动化发布流程,避免人工地打包、上传、解压、改生产配置这些重复性的人工操作。
在自动化发布中,Phing是个不错的尝试。
以下是我某个项目中的使用配置,出于对项目的保护,部分数据已删除,但仍然可以参考。
###(1)发布配置 - build.xml
主要的操作有:
+ 1. 备份当前代码,并删除一天前的备份
+ 2. 从SVN签出最新的发布代码
+ 3. 执行配置检测脚本
+ 4. 代码发布切换,并替换使用线上配置文件
+ 5. 移除单元测试初始化文件,以免误执行
```javascript
<?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
主要操作:
+ 1. 回滚到上一个版本
```javascript
<?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:接口压力测试与可视化图表
可以通过以下的脚本来进行,使用示例:
```javascript
$ ./autobench.sh
Usage: ./autobench.sh <host> <uri>
- ./autobench.sh www.baidu.com /index.php
```
参数可以自行调整。
###(1)利用bench2graph生成可视化图表
####纯PHP访问 - 入口欢迎接口
![a pic](http://webtools.qiniudn.com/1421422942BjP7K5M5.jpg)
####mysql访问 - 事件获取接口
![a pic](http://webtools.qiniudn.com/14214229738ftM0Nck.jpg)
####带MC缓存的访问 - 应用入口 - 带缓存的身份token验证
![a pic](http://webtools.qiniudn.com/1421424027OYV4Ae5i.jpg)
###(2)详细的数据报表
```javascript
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)附脚本
```javascript
#!/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
```javascript
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%
对应的图表如下:
![a pic](http://webtools.qiniudn.com/phalapi_xhprxf.jpg)
从中可以看出,主要的耗时途径在于文件的加载,下面将进一步探讨。
###(4)Top 1耗时深入
![a pic](http://webtools.qiniudn.com/top1_sheet-small.png)
所加载的文件如下:
![a pic](http://webtools.qiniudn.com/top1_loader.png)
##2.22.5 Jenkis和Sonar:持续集成和静态代码分析
PhalApi从来不会隐藏自己的设计,当然,我们也不会隐藏我们内部的各个细节以及存在的问题。
但和其他隐藏了技术债务的框架相比,PhalApi敢于展示自己的静态代码分析报告,并且它也是做得相当出色的。
以下截图来自 GIT@OSC 上的静态代码分析:
![a pic](http://webtools.qiniudn.com/sonar_code_analysis.png)
当你的项目很重要时,也可以使用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
以下是针对本框架核心代码所做的分析报告:
![a pic](http://7qnay5.com1.z0.glb.clouddn.com/QQ截图20150807230905.jpg)
![a pic](http://7qnay5.com1.z0.glb.clouddn.com/QQ截图20150807230920.jpg)
PS:从报告的评估可以看出,我们的框架明显具有相当 高的可维护性。
- 欢迎使用PhalApi!
- 接口,从简单开始!
- [1.1]-下载与安装
- [1.2]-创建一个自己的项目
- [1.3]-在线体验
- [1.4]-文档、帮助和官网
- [1.10]-对PhalApi框架的抉择
- [1.11]-快速入门(backup)
- [1.12]-参数规则:接口参数规则配置
- [1.13]-统一的接口请求方式:_sevice=XXX.XXX
- [1.14]-统一的返回格式和结构:ret-data-msg
- [1.15]-数据库操作:基于NotORM的使用及优化
- [1.16]-配置读取:内外网环境配置的完美切换
- [1.17]-日记纪录:简化版的日记接口
- [1.18]-快速函数:人性化的关怀
- [1.19]-DI服务速查:各资源服务一览表
- [1.20]-DB操作:数据库基本操作速查
- [1.21]-类的自动加载:遵循PEAR包的命名规范
- [1.22]-签名验证:自定义签名规则
- [1.23]-请求和响应:GET和POST两者皆可得及超越JSON格式返回
- [1.24]-缓存策略:更灵活地可配置化的多级缓存
- [1.25]-国际化翻译:为走向国际化提前做好翻译准备
- [1.26]-数据安全:数据对称加密方案
- [1.27]-精益开发:更富表现力的Model层和重量级数据获取的应对方案
- [1.28]-COOKIE:对COOKIE原生态的支持及记忆加密升级版
- [1.29]-开放与封闭:多入口和统一初始化
- [1.30]-保持的力量:接口开发最佳实践
- [1.31]-新型计划任务:以接口形式实现的计划任务
- [2.11]-核心思想:DI依赖注入-让资源更可控
- [2.12]-海量数据:可配置的分库分表
- [2.13]-接口调试:在线SQL语句查看与性能优化
- [2.14]-测试驱动开发:意图导向编程下的接口开发
- [2.15]-演进:新型计划任务续篇
- [2.16]-领域驱动设计:应对复杂领域业务的Domain层
- [2.17]-微服务:Api接口服务层
- [2.18]-定制化:资源服务的再实现
- [2.19]-扩展库:可重用的扩展类库
- [2.20]-约定编程:架构明显的编程风格
- [2.21]-服务器统一部署方案简明版:CentOs---Nginx---php-fpm---MySql-[--Memcached]
- [2.22]-更多工具:精益项目和团队建设
- [3.1]-扩展类库:微信开发
- [3.2]-扩展类库:代理模式下phprpc协议的轻松支持
- [3.3]-扩展类库:基于PHPMailer的邮件发送
- [3.4]-扩展类库:优酷开放平台接口调用
- [3.5]-扩展类库:七牛云存储接口调用
- [3.6]-扩展类库:新型计划任务
- [3.8]-扩展类库:用户、会话和第三方登录集成
- [3.9]-扩展类库:swoole支持下的长链接和异步任务实现
- [3.11]-扩展类库:基于FastRoute的快速路由
- [4.2]-开发实战2:模拟优酷开放平台接口项目开发
- [4.3]-开发实战3:一个简单的小型项目开发(奔跑吧兄弟投票活动)
- [5.1]-架构与思想:PhalApi核心设计和思想解读
- [5.2]-杂谈:扯一些PhalApi的前世和今生
- [5.3]-框架总结:术语表和PHP开发建议
- [5.4]-许可
- [5.5]-联系和加入我们
- [5.6]-更新日记
- [5.8]-致框架贡献者:加入PhalApi开源指南
- [6.1]-基于接口查询语言的SDK包
- [6.2]-SDK包(JAVA版)
- [6.3]-SDK包(PHP版)
- [6.4]-SDK包(Objective-C版)
- [6.5]-SDK包(javascript版)
- [6.6]-SDK包(Ruby版)
- [8.1]-PhalApi视频教程
- 附录1:接口文档参考模板