PHP代码编写自动化测试被认为是一个最佳实践,可以帮助你构建出高质量的应用。自动化测试可以帮助你确认没有因为重构或添加 新功能而破坏原有功能,所以应该重视自动化测试。

PHP有多种类型的测试工具和框架可以使用,具体方法各有区别——但是它们的目标都是避免手工测试,满足大型QA组织的需求,保证最新的 更改没有破坏已有功能。

测试驱动开发

Wikipedia的定义:

测试驱动开发(TDD)是以非常短的开发周期,不断进行迭代的软件开发流程:首先开发者针对改进或新功能编写失败的自动化测试用例,然后编写代码使测试用例通过, 最后重构代码,让代码满足可接受的标准。Kent Beck,该技术的创建者或者说重新发现者,在2003年声明TDD鼓励简单的设计和提振信心。

目前对应用有多种类型的测试:

单元测试

单元测试是从编写开始,贯穿于整个开发周期的一种用于保证函数、类和方法的行为与预期一致的编程方法。通过检查各个函数和方法的输入和输出值,你可以保证它们 内部逻辑已经正确执行;通过依赖注入、编写mock类和stubs,你可以验证依赖是否已经正确处理,提高测试覆盖率。

在编写一个类或函数的时候,应该为它的每一个行为创建一个单元测试,至少你要保证它收到错误参数时能够触发错误,而参数正确时能正常工作。这可以帮你在后面 修改类或函数的时候,确认已有功能仍然正常工作。PHP中var_dump()的功能与此类似,但是它是无法用于创建应用的。

单元测试的另外一个用武之地是在给开源项目贡献代码时,如果你编写一个测试,证明代码存在bug,然后修复代码,让测试通过,这样该补丁被接受的概率要高很多。 如果你的项目接受人家的补丁,你应该把单元测试作为项目的一项要求。

PHPUnit是PHP应用的单元测试框架的业界标准,其他几个可选框架是:

集成测试

Wikipedia的定义:

集成测试(也称集成与测试,缩写为I&T)是把各个独立模块集成在一起,作为一个整体进行测试的软件测试阶段,它处于单元测试和验收测试之间。集成测试把已经 做过单元测试的模块集成在一块,然后运行集成测试用例,最终输出一个可以进行系统测试的系统。

很多单元测试工具同时也可以用于集成测试,并且原理也是相通的。

功能测试

有时也称为验收测试,使用工具创建自动化的测试用例,然后在真实的系统上运行,这一点与单元测试验证单个模块的正确性和集成测试验证模块间交互的正确性是有 区别的,这些工具通常使用真实的数据集来模拟真实用户的使用行为来验证系统的正确性。

功能测试工具

行为驱动开发

行为驱动开发(BDD)有两种方式:SpecBDD和StoryBDD。SpecBDD关注技术行为或代码,而StoryBDD关注业务、特性和交互,这两种方式都有对应的PHP框架。

采用StoryBDD,开发者编写人类可读的故事来描述应用的行为,然后这些故事可以作为应用的测试用例。PHP中用于StoryBDD编程的框架是Behat,从Ruby 的Cucumber项目演化而来,实现了Gherkin DSL来描述特性行为。

采用SpecBDD,开发者编写规格说明来描述实际代码的行为,与测试一个函数或方法不同,规格描述了一个函数或方法应该具有的行为。PHP中的PHPSpec框 架提供该编程方式的支持,它也是从Ruby的RSpec project演化而来。

BDD链接

  • Behat, the StoryBDD framework for PHP, inspired by Ruby’s Cucumber project;
  • PHPSpec, the SpecBDD framework for PHP, inspired by Ruby’s RSpec project;
  • Codeception is a full-stack testing framework that uses BDD principles.

测试辅助工具

除了测试驱动和行为驱动开发框架,还有大量的通用框架和函数库,可以在各种开发方法下使用。

工具链接

此文只当是一个mark吧

在mac和linux上软链接的使用基本是相同的,有一点不同的在权限方面:

1 linux的软链文件不能修改权限

详见man chmod :

chmod never changes the permissions of symbolic links; the chmod system call cannot change their permissions. This is not a problem since the permissions of symbolic links are never used. However, for each symbolic link listed on the command line, chmod changes the permissions of the pointed-to file. In contrast, chmod ignores symbolic links encountered during recursive directory traversals.

2 mac的软链文件可以用chmod设置权限  chmod -h 777 ./symlink

详见man chmod :

-h If the file is a symbolic link, change the mode of the link itself rather than the file that the link points to.

不会shell害死人啊,想按时间生成log文件都能出错。从网上找了很多示例,终于在N多不靠谱的中找到一个靠谱的。

原文如下:

在 Windows、Linux 操作系统,分别利用BAT批处理文件和Shell脚本,生成类似“20110228_082905.txt”以“年月日_时分秒”命名的文件。

Windows BAT批处理文件:
@echo off
set time_hh=%time:~0,2%
if /i %time_hh% LSS 10 (set time_hh=0%time:~1,1%)
set filename=%date:~,4%%date:~5,2%%date:~8,2%_%time_hh%%time:~3,2%%time:~6,2%
echo test >> %filename%.txt


Linux Shell 脚本:
#!/bin/sh
echo test >> $(date -d "today" +"%Y%m%d_%H%M%S").txt

via:http://blog.s135.com/post/459/

服务器上一直用着mysql_pconnect,之前听说它会出现各种各样的问题,但服务器一直没事,也就没去管。今天看这篇文章,才知道原来mysql_pconnect有这么多的道道。

原文地址:http://www.cnblogs.com/funlake/archive/2011/09/08/2171822.html

  php的mysql持久化连接,美好的目标,却拥有糟糕的口碑,往往令人敬而远之。这到底是为啥么。近距离观察后发现,这家伙也不容易啊,要看apache的脸色,还得听mysql指挥。

  对于做为apache模块运行的php来说,要实现mysql持久化连接,首先得取决于apache这个web服务器是否支持Keep-Alive。

  Keep-Alive

  Keep-Alive是什么东西?它是http协议的一部分,让我们复习一下没有Keep-Alive的http请求,从客户在浏览器输入一个有效url地址开始,浏览器就会利用socket向url对应的web服务器发送一条tcp请求,这个请求成功一次就得需要来回握三次手才能确定,成功以后,浏览器利用socket tcp连接资源向web服务器请求http协议,发送以后就等着web服务器把http返回头和body发送回来,发回来后浏览器关闭socket连接,然后做http返回头和body的解析工作,最后呈现在浏览器上的就是漂亮的页面了。这里面有什么问题呢?tcp连接需要三次握手,也就是来回请求三次方能确定一个tcp请求是否成功,然后tcp关闭呢?来回需要4次请求才能完成!每次http请求就3次握手,4次拜拜,这来来回回的不嫌累啊,多少时间和资源都被浪费在socket连接关闭上了,能不能一次socket tcp连接发送多次http请求呢?于是Keep-Alive就应运而生,http/1.0里需要客户端自己在请求头加入Connection:Keep-alive方能实现,在这里我们只考虑http1.1了,只需要设置一下apache,让它默认就是Keep-Alive持久连接模式(apache必须1.2+才能支持Keep-Alive).在httpd.conf里找到KeepAive配置项,果断设置为On,MaxKeepAliveRequests果断为0(一个持久tcp最多允许的请求数,如果过小,很容易在tcp未过期的情况下,达到最大连接,那下次连接就又是新的tcp连接了,这里设置0表示不限制),然后对于mysql_pconnect最重要的选项KeepAliveTimeout设置为15(表示15秒).

  好了,重启apache,测试一下,赶紧写行东西

<?php
    echo "Apache进程号:".getmypid();
?>

很简单,获取当前php执行者(apache)的进程号,用浏览器浏览这个页面,看到什么?对,有看到一串进程号数字,15秒内,连续刷新页面,看看进程号有无变化?木有吧?现在把手拿开,交叉在胸前,度好时间,1秒,2秒,3,…15,16。好,过了15秒了,再去刷新页面,进程号有没有变化?变了!又是一个新的apache进程了,为什么15秒后就变成新的进程了?记得我们在apache里设置的KeepAliveTimeout吗?它的值就是15秒.现在我们应该大致清楚了,在web服务器默认打开KeepAlive的情况下,客户端第一次http成功请求后,apache不会立刻断开socket,而是一直监听来自这一客户端的请求,监听多久?根据KeepAliveTimeout选项配置的时间决定,一旦超过这一时间,apache就会断开socket了,那么下次同一客户端再次请求,apache就会新开一个进程来相应。所以我们之前15内不停的刷新页面,看到的进程号都是一致的,表明是浏览器请求给了同一个apache进程。

  浏览器是怎么知道不需要重新进行tcp连接就可以直接发送http请求呢?因为http返回头里就会带上Connection:keep-alive,Keep-alive:15两行,意思就是让客户端浏览器明白,这次socket连接我这边还没关闭呢,你可以在15内继续使用这个连接,并发送http请求,于是乎浏览器就知道应该怎么做了.

  php怎么做

  那么,php的mysql连接资源是怎么被hold住的呢,这需要查看php的mysql_pconnect的函数代码,我看了下,大概的做法就是根据当前apache进程号,生成hash key,找hash表内有无对应的连接资源,没有则推入hash表,有则直接使用。有些代码片段可以说明(具体可查看php5.3.8源码ext/mysql/php_mysql.c文件690行php_mysql_do_connect函数)

    #1.生成hash key
        user=php_get_current_user();//获取当前php执行者(apache)的进程唯一标识号
        hashed_details_length = spprintf(&hashed_details, 0, "mysql__%s_", user);//hashed_details就是hash key
    #2.如果未找到已有资源,就推入hash表,名字叫persistent_list,如果找到就直接使用
         /* try to find if we already have this link in our persistent list */
         if (zend_hash_find(&EG(persistent_list), hashed_details, hashed_details_length+1, (void **) &le)==FAILURE) {  /* we don't */
            ...
            ...
            /* hash it up(推入hash表) */
            Z_TYPE(new_le) = le_plink;
            new_le.ptr = mysql;
            if (zend_hash_update(&EG(persistent_list), hashed_details, hashed_details_length+1, (void *) &new_le, sizeof(zend_rsrc_list_entry), NULL)==FAILURE) {
                ...
                ...
            }

         }else{/* The link is in our list of persistent connections(连接已在hash表里)*/
            ...
            ...
            mysql = (php_mysql_conn *) le->ptr;//直接使用对应的sql连接资源
            ...
            ...

         }

zend_hash_find比较容易看明白,原型是zend_hash_find(hash表,key名,key长,value);如果找到,value就有值了。

      mysql的wait_timeout和interactive_timeout

  说完Keep-Alive,该到mysql家串串门了,说的是mysql_pconnect,怎么能绕开mysql的设置。

  影响mysql_pconnect最重要的两个参数就是wait_timeout和interactive_timeout,它们是什么东西?先撇一边,首先让我们把上面的代码改动一下php代码

<?php
    $conn = mysql_pconnect("localhost","root","123456") or die("Can not connect to mysql");
    echo "Mysql线程号:".mysql_thread_id($conn)."<br/>";
    echo "Apache进程号".getmypid();
?>

以上的代码没啥好解释的,让我们用浏览器浏览这个页面,看到什么?看到两个显眼的数字。一个是mysql线程号,一个是apache进程号,好了,15秒后再刷新这个页面,发现这两个id都变了,因为已经是新的apache进程了,进程id是新的,hash key就变了,php只好重新连接mysql,连接资源推入persistent list。如果15内刷新呢?apache进程肯定不变,mysql线程号会变吗?答案得问mysql了。首先这个mysql_thread_id是什么东西?shell方式登录mysql后执行命令’show processlist’,看到了什么?

mysql> show processlist;
+-----+------+-----------+------+---------+------+-------+------------------+
| Id  | User | Host      | db   | Command | Time | State | Info             |
+-----+------+-----------+------+---------+------+-------+------------------+
| 348 | root | localhost | NULL | Query   |    0 | NULL  | show processlist |
| 349 | root | localhost | NULL | Sleep   |    2 |       | NULL             |
+-----+------+-----------+------+---------+------+-------+------------------+

,发现了很重要的信息,这个processlist列表就是记录了正在跑的线程,忽略Info列为show processlist那行,那行是你当前shell登录mysql的线程。php连接mysql的线程就是Id为349那行,如果读者自己做测试,应该知道这个Id=349在你的测试环境里是另外一个值,我们把这个值和网页里输出的mysql_thread_id($conn)做做比较,对!他们是一样的。接下来最重要的是观察Command列和Time列,Command = Sleep,表明什么?表明我们mysql_pconnect连接后就一直在sleep,Time字段就告诉我们,这个线程Sleep了多久,那么Sleep了多久这个线程才能作废呢?那就是wait_timeout或者interactive_timeout要做的工作了,他们默认的值都是8小时,天啊,太久了,所以如果说web服务器关掉KeepAlive支持,那个这个processlist很容易就被撑爆,就爆出那个Too many connections的错误了,max_connectiosns配置得再多也没用。为了观察这两个参数,我们可以在mysql配置文件my.cnf里设置这两个值,找到[mysqld]节点,在里面设置多两行

interactive_timeout = 60
wait_timeout        = 30

配置完后,重启mysql,shell登录mysql,这时候show processlist可以发现只有当前线程。然后运行那个带有mysql_pconnect的php页面,再回来mysql端show processlist可发现,多了一个Commond为Sleep的线程,不停的show processlist(方向键上+enter键)观察Time列的变化2,5,10..14!,突然那个Sleep线程程被kill掉了,咋回事,还没到30秒呢,噢!忘了修改一下apache keepalive的参数了,把KeepAliveTimeOut从15改成120(只为观察,才这么改),重启apache.刷新那个页面,好,开始不停的show processlist,2..5..10..14,15,..20…26….28,29!线程被kill,这次是因为wait_timeout起了作用,浏览器那边停了30秒,30秒内如果浏览器刷新,那这个Time又会从0开始计时。这种连接不属于interactive connection(mysql shell登录那种连接就属于interactive connection),所以采用了wait_timeout的值。如果mysql_pconnect的第4个参数改改呢

<?php
$conn = mysql_pconnect('localhost','root','123456',MYSQL_CLIENT_INTERACTIVE);
echo "Mysql线程号:".mysql_thread_id($conn)."<br/>";
echo "Apache进程号:".getmypid();
?>

刷新下页面,mysql那边开始刷show processlist,这回Time > 30也不会被kill,>60才被kill了,说明设置了MYSQL_CLIENT_INTERACTIVE,就会被mysql视为interactive connection,那么这次php的mysql连接在120秒内未刷新页面的情况下,何时作废将取决于mysql的interactive_timeout的配置值。

  总结

  #1.php的mysql_pconnect要达到功效,首先必须保证apache是支持keep alive的,然后KeepAliveTimeOut应该设置多久呢,要根据自身站点的访问情况做调整,时间太短,keep alive没啥意义,时间太长,就很可能为一个闲客户端连接牺牲很多服务器资源,毕竟hold住socket监听进程是要消耗cpu内存的.

  #2.apache的KeepAliveTimeOut配置得和mysql的time out配置要有个平衡点,联系以上的观察,假设mysql_pconnect未带上第4个参数,如果apache的KeepAliveTimeOut设置的秒数比wait_timeout小,那真正对mysql_pconnect起作用的是apache而不是mysql的配置.这时如果mysql的wait_timeout偏大,并发量大的情况下,很可能就一堆废弃的connection了,mysql这边如果不及时回收,那就很可能Too many connections了.可是如果KeepAliveTimeOut太大呢,又回到之前的问题,所以貌似Apache.KeepAliveTimeOu不要太大,但比Mysql.wait_timeout 稍大,或者相等是比较好的方案,这样可以保证keep alive过期后,废弃的mysql连接可以及时被回收. 

  后记

  Pdo数据库的长连接机制是否和mysql_pconnect一样?经过试验观察和源码探究,发现也是一样的处理方式。

服务器用的centOS,平时用SSH管理。在命令行下目录用蓝色显示,很难看清。

默认的命令行配色

GOOGLE了一下,原来很多人跟我一样有同感。

其实修改起来挺简单(虽然效果还是很丑…但至少看起来没那么累了)

1.cp /etc/DIR_COLORS $HOME/.dir_colors (很多人是直接改DIR_COLORS,但这样是没有用的)

1. vim $HOME/.dir_colors

2. 找到 DIR 01;34,修改为DIR 01;37;44,即白字蓝底,保存退出

3. reboot重启,或用eval `dircolors $HOME/DIR_COLORS`(`是键盘右上角ESC下面的键),重新载入设置,就可以ls查看到效果了

修改后效果

有关/etc/DIR_COLORS的详情配置,可以到这里查看http://linux.chinaunix.net/techdoc/system/2008/12/29/1055585.shtml

在寻求ubuntu下Firefox翻墙时发现,原来在linux下翻墙是如此的容易!

本文面向的用户:使用Ubuntu作为操作系统并且使用Firefox作为常用浏览器,且有SSH账号的同学!

一、在终端中配置SSH

假设你的帐号为:enjoyphp ||服务器地址为:enjoyphp.com ||密码为:123456
  1. 打开终端:应用程序-附件-终端
  2. 在终端中输入:sudo ssh -qTfnN -D 7070 enjoyphp@enjoyphp.com

  3. 稍后会出现提示: Are you sure you want to continue connecting (yes/no)?
  4. 输入:yes (注意,单单输入 y 是不行地~)

  5. 然后提示输入密码: enjoyphp@enjoyphp.com’s password:
  6. 输入:123456

第三步:配置Firefox浏览器

假设你正使用Firefox浏览器阅读本文。

一键安装:http://autoproxy.mozdev.org/latest.xpi

xpi-offical

点击立即安装,安装后,重新启动Firefox。然后你会看到如下对话框,选择gfwlist (P.R.China)后,点击确定。

gfwlist

接着你会看到Firefox主界面右上角出现有一个“福”字图案,点击“福”。

fu

点击“代理服务器——编辑代理服务器”。

edit

随即出现如下画面,你会看到如GAppProxy、Tor和Your Freedom这样一系列代理服务器名称。

before

将GAppProxy一栏的参数修改为如下图所示。

after

修改完毕后,点击确定。至此配置已全部就绪。

大多人浏览网页如果超过3秒打不开就会离开,Google为此推出了一款apache加速模块,可以有效将网页加载速度提高50%.
网页提速的问题是一个复杂多样的问题,有很多解决方法,往往关系到网站系统程序,服务器硬件,网络传输速度等方面,而Google这款加速模块简单的解决了许多复情况的问题:

•如果你的网站采用apache构建服务器,不需要对网站CMS系统进行处理即可应用
•加速模块可以自行对网络传输的html字节优化及对图象,css进入压缩优化传输
•智能缓存是一大亮点,它可以自动智能缓存,加速下载
下面介绍一下所有特点功能

优化缓存
•缓存扩展
•压缩处理CSS
•优化javascript最大限度的减少重复请求
•自动缓存CSS
•JavaScript内嵌技术
有效载荷尺寸最小化
•压缩空白
•合并头信息
•附加属性
•内建核心Javascript
•优化图像下载
•跳地非法字符
•重写优化CSS

访问:mod_pagespeed

centos

centos

这个。。虽说是出了新版本,但让我挺郁闷。好不容易把centos5.4下载下来,并配置好了,也就是在我刚配置好的一霎那..看到官方推出了centos5.5版。这也太巧了。
不过总归是很期待这个版本的,RHEL 5.5在3月底就发布了,所以一直想着centos能紧跟,现在过去一个半月发布,也还算是跟得挺紧的。

mirrors.163.com已经有了5.5的更新了,需要的朋友可以直接去下了:http://mirrors.163.com/centos/5.5/isos/

该版本基于 Red Hat Enterprise Linux 5.5,“是 CentOS 5 发行系列的第五次更新。它包含了很多错误修正、升级和新功能”。

有关 CentOS 5.5 的变化详情,可查阅其发 布公告发 行注记

如果想在CentOS中安装最新版本的nginx,那用yum的方式安装就不行了,目前yum中的版本是0.6,而最新nginx版本是0.8.36。所以我们只能通过编译安装,但编译安装后问题就来了,不能像yum安装的那样通过/etc/init.d/nginx start(或stop或restart)。唯一的办法就是自己创建个脚本来实现这些功能:

1.停止nginx,推荐用这个命令


sudo kill `cat /usr/local/nginx/logs/nginx.pid`

2.创建/etc/init.d/nginx文件


sudo vim /etc/init.d/nginx

文件中添加如下内容:


#!/bin/sh
#
# nginx - this script starts and stops the nginx daemin
#
# chkconfig:   - 85 15 
# description:  Nginx is an HTTP(S) server, HTTP(S) reverse 
#               proxy and IMAP/POP3 proxy server
# processname: nginx
# config:      /usr/local/nginx/conf/nginx.conf
# pidfile:     /usr/local/nginx/logs/nginx.pid

# Source function library.
. /etc/rc.d/init.d/functions

# Source networking configuration.
. /etc/sysconfig/network

# Check that networking is up.
[ "$NETWORKING" = "no" ] && exit 0

nginx="/usr/local/sbin/nginx"
prog=$(basename $nginx)

NGINX_CONF_FILE="/usr/local/nginx/conf/nginx.conf"

lockfile=/var/lock/subsys/nginx

start() {
    [ -x $nginx ] || exit 5
    [ -f $NGINX_CONF_FILE ] || exit 6
    echo -n $"Starting $prog: "
    daemon $nginx -c $NGINX_CONF_FILE
    retval=$?
    echo
    [ $retval -eq 0 ] && touch $lockfile
    return $retval
}

stop() {
    echo -n $"Stopping $prog: "
    killproc $prog -QUIT
    retval=$?
    echo
    [ $retval -eq 0 ] && rm -f $lockfile
    return $retval
}

restart() {
    configtest || return $?
    stop
    start
}

reload() {
    configtest || return $?
    echo -n $"Reloading $prog: "
    killproc $nginx -HUP
    RETVAL=$?
    echo
}

force_reload() {
    restart
}

configtest() {
  $nginx -t -c $NGINX_CONF_FILE
}

rh_status() {
    status $prog
}

rh_status_q() {
    rh_status >/dev/null 2>&1
}

case "$1" in
    start)
        rh_status_q && exit 0
        $1
        ;;
    stop)
        rh_status_q || exit 0
        $1
        ;;
    restart|configtest)
        $1
        ;;
    reload)
        rh_status_q || exit 7
        $1
        ;;
    force-reload)
        force_reload
        ;;
    status)
        rh_status
        ;;
    condrestart|try-restart)
        rh_status_q || exit 0
            ;;
    *)
        echo $"Usage: $0 {start|stop|status|restart|condrestart|try-restart|reload|force-reload|configtest}"
        exit 2
esac

3.增加可执行权限


sudo chmod +x /etc/init.d/nginx 

4.设置自启动


sudo /sbin/chkconfig nginx on 

5.使用举例

完成上面这些设置后,我们就可以像yum安装后那样,使用如下的命令


sudo /etc/init.d/nginx start  
...  
sudo /etc/init.d/nginx stop  
...  
sudo /etc/init.d/nginx restart  
...  
sudo /etc/init.d/nginx reload  
...  
sudo /etc/init.d/nginx status  
...  
sudo /etc/init.d/nginx configtest 

《The Linux Command Line》由 William E. Shotts, Jr. 所著,William E. Shotts. Jr. 是著名的 LinuxCommand.org 网站的维护者,相信资深的 Linux CLI 控都不会陌生。这本《The Linux Command Linux》有 500 多页,对 Linux 命令行进行了全面的介绍,但是写得深入浅出,不仅适合 Linux CLI 新手阅读,就算是老鸟也能从中有所崭获。

本书是免费的,为 PDF 格式,可从这里下载

不过这个网站经常性的不稳定,可能是中国长城太宽了的原因。下不了的可以PM我