codecamp

更多工具:精英项目和团队建设

2.22.1 PHPUnit:自动化单元测试

目前核心框架单元测试的覆盖率(高达90%以上!!!此处应该有掌声~): a pic

注意,此测试截图并不是最新的,但我们一直都在致力坚持单元测试。
这一点,你可以在单元测试的代码中找到证明。

2.22.2 Phing:一键部署、快速发布

无论如何,都应该走自动化发布流程,避免人工地打包、上传、解压、改生产配置这些重复性的人工操作。

在自动化发布中,Phing是个不错的尝试。

以下是我某个项目中的使用配置,出于对项目的保护,部分数据已删除,但仍然可以参考。

(1)发布配置 - build.xml

主要的操作有:

    1. 备份当前代码,并删除一天前的备份
    1. 从SVN签出最新的发布代码
    1. 执行配置检测脚本
    1. 代码发布切换,并替换使用线上配置文件
    1. 移除单元测试初始化文件,以免误执行
<?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. 回滚到上一个版本
<?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访问 - 入口欢迎接口

a pic

mysql访问 - 事件获取接口

a pic

带MC缓存的访问 - 应用入口 - 带缓存的身份token验证

a pic

(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 NameCallsCalls%Incl. Wall Time(microsec)IWall%(microsec)Excl. Wall TimeEWall%
PhalApi_Loader::loadClass103.00%3,02038.40%1,03813.20%
PhalApi_Loader::loadClass141.20%78510.00%3985.10%
run_init::Public/init.php10.30%3,91549.70%3274.20%
file_exists185.30%2493.20%2493.20%
main()10.30%7,873100.00%2483.20%
load::zh_cn/common.php20.60%2373.00%2373.00%
PhalApi_Loader::load92.70%3,38042.90%2262.90%
PhalApi_DI::get92.70%1,26816.10%2232.80%
PhalApi_Translator::addMessage20.60%5226.60%1361.70%
DI154.40%6458.20%1341.70%
class_exists113.30%1,38317.60%1301.70%
load::Config/sys.php10.30%1201.50%1201.50%

对应的图表如下:
a pic
从中可以看出,主要的耗时途径在于文件的加载,下面将进一步探讨。

(4)Top 1耗时深入

a pic

所加载的文件如下:
a pic

2.22.5 Jenkis和Sonar:持续集成和静态代码分析

PhalApi从来不会隐藏自己的设计,当然,我们也不会隐藏我们内部的各个细节以及存在的问题。
但和其他隐藏了技术债务的框架相比,PhalApi敢于展示自己的静态代码分析报告,并且它也是做得相当出色的。

以下截图来自 GIT@OSC 上的静态代码分析: a pic

当你的项目很重要时,也可以使用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
a pic

PS:从报告的评估可以看出,我们的框架明显具有相当 高的可维护性。

服务器统一部署方案简明版:CentOs + Nginx + php-fpm + MySql [+ Memcached]
微信开发
温馨提示
下载编程狮App,免费阅读超1000+编程语言教程
取消
确定
目录

八、视频教程

关闭

MIP.setData({ 'pageTheme' : getCookie('pageTheme') || {'day':true, 'night':false}, 'pageFontSize' : getCookie('pageFontSize') || 20 }); MIP.watch('pageTheme', function(newValue){ setCookie('pageTheme', JSON.stringify(newValue)) }); MIP.watch('pageFontSize', function(newValue){ setCookie('pageFontSize', newValue) }); function setCookie(name, value){ var days = 1; var exp = new Date(); exp.setTime(exp.getTime() + days*24*60*60*1000); document.cookie = name + '=' + value + ';expires=' + exp.toUTCString(); } function getCookie(name){ var reg = new RegExp('(^| )' + name + '=([^;]*)(;|$)'); return document.cookie.match(reg) ? JSON.parse(document.cookie.match(reg)[2]) : null; }