存档

‘程序员’ 分类的存档

什么样的测试用例是好的

2010年8月23日 1 条评论

作为测试人员,设计测试用例是干活的第二步(第一步当然是了解测试对象嘿嘿),这一步做的好与否,对后续工作起着决定作用,那么如何评价一个测试用例的好坏,或者说,设计的成功与否呢,本文大概讨论一下,抛砖引玉吧,记录在这里,看看是不是可以作为一次团队讨论的话题。

在此之前,我们需要明确测试工程师的工作原则:用最小的成本找出最多的问题。

1.用例覆盖程度

毫无疑问,这一点应该是最重要的,无需多说,覆盖率最大化是一套测试用例的最重要评价标准,如果漏测就杯具了。

2.用例是否已经达到工作量最小化

在满足用例覆盖程度最大化的前提下,应该尽量减小执行用例所需要的工作量。这些方面的方法有不少,如条件覆盖,分支覆盖,正交覆盖等方法。面对不同的测试对象,也有不同的方法来保证:对于网页背后的php逻辑,可以通过在网页上测试后,用一些工具比如xdebug来统计代码覆盖率;对于向外提供接口的server,采用的方式就是分析在外面暴露的接口设计用例,大致的通过接口参数来估计一下分支判断的情况。

3.用例的分类以及描述是否足够清晰

用例的分类,在这里是指相同类型的用例是否放在一起了。例如:接口类的用例,参数的取值范围是1-3,但是现在却传入4;数据类用例,状态机现在位于状态2,却要求状态跳转到无法到达的4;逻辑类用例,正常功能的产出等。将相同类型的用例放在一起,有助于理清思路,清楚了解用例设计是否完备。

用例的描述,是指描述的清晰程度是否能够形成文档。例如上面参数取值范围的例子,用例这样写:“传入错误的值”或者“传入非1-3的值”,明显没有写成“传入值4”有效。这与写程序一样,总是写闭区间的范围而不是开区间。

4.用例是否表明了测试目的

写明用例的测试目的,对文档的易于理解性和工作交接的好处不言而喻,现代软件工程不可能只有一个人在做事情,项目于人员的变动也是难免的。在过程中留下足够的信息,可以在后续工作提高很多效率。

5.测试用例的易于维护性

如果被测对象有所升级,测试用例的说明或者脚本是不是容易维护呢?例如在有状态机的情况下,测试用例之间是相互依赖的(即需要一定的执行顺序),这样被依赖的用例修改后,后端不需要同步根据修改。而如果用例之间没有相互依赖关系(如用例是自己造的数据,不是依赖于前端的产出),可能一旦有变化,就需要修改这两个。当然,这两种情况不能绝对的说哪种好,是需要看实际使用时候的情况进行取舍的。不过,通过一些系统性的工具支持,也会出现一种做法绝对性的好于另外一种的情况,情况很多,做法也有很多,在这里就不多说了。

说了这么多,其实这个第二步,还是严重依赖于第一步的,如果对测试对象的需求,实现等都不了解,设计用例也就无从谈起了。

---------------------------------------------------------------
本站作品根据创作共同协议进行授权, 转载时请务必以超链接形式标明文章原始出处
原文地址:http://www.mirecle.com/2010/08/23/what-is-a-good-test-case.html
---------------------------------------------------------------

分类: 程序员 标签:

sql运行简单封装

2010年7月23日 1 条评论

作为一个QA,我本来是很少写代码的,不过这段代码用的次数比较多,每次用的时候都改一些,比较烦,所以整理了一个通用的,作为个人代码库的第一块石头吧
升级于2010-7-26,修复bug

class sql_runner{

	private static $_arr_self = array();

	private $_addr = false;
	private $_user = false;
	private $_passwd = false;
	private $_db_connection = false;

	static function get_instance($addr, $user, $passwd){
		$key = $addr.'#'.$user.'#'.$passwd;
		if(false === array_key_exists($key, self::$_arr_self)){
			sql_runner::$_arr_self[$key] = new sql_runner($addr, $user, $passwd);
		}

		return sql_runner::$_arr_self[$key];
	}

	private function __construct($addr, $user, $passwd){
		$this->_addr = $addr;
		$this->_user = $user;
		$this->_passwd = $passwd;
	}

	public function run_sql($sql){

		if(false === $this->_db_connection || !mysql_ping($this->_db_connection)){
			UB_LOG_DEBUG("connecting db $this->_addr, $this->_user");
			$this->_db_connection = mysql_connect($this->_addr, $this->_user, $this->_passwd);

			if(false === $this->_db_connection){
				UB_LOG_FATAL("connect db failed: ".mysql_error());
				return false;
			}else{
				mysql_set_charset('latin1', $this->_db_connection);
			}
		}

		$result = false;
		$result = mysql_query($sql, $this->_db_connection);
		if(false === $result){
			UB_LOG_FATAL("[$sql] execute failed:". mysql_error($this->_db_connection)."\n");
			return false;
		}

		$result_arr = array();
		if(is_resource($result)){
			while($row = mysql_fetch_assoc($result)){
				$result_arr[] = $row;
			}
			mysql_free_result($result);
		}

		UB_LOG_DEBUG("[$sql] execute succed, selected result:".print_r($result_arr, true));
		return $result_arr;
	}

}

/**for log functions*/
if(!function_exists('UB_LOG_DEBUG')){
	function UB_LOG_DEBUG($log){
		print($log);
	}
}
if(!function_exists('UB_LOG_FATAL')){
	function UB_LOG_FATAL($log){
		print($log);
	}
}

---------------------------------------------------------------
本站作品根据创作共同协议进行授权, 转载时请务必以超链接形式标明文章原始出处
原文地址:http://www.mirecle.com/2010/07/23/sql-to-run-a-simple-package.html
---------------------------------------------------------------

分类: 程序员 标签: ,

sigterm sigint sigkill 区别

2010年5月20日 6 条评论

我看网上应该有不少搜索这个区别的问题,但是回答的都不全面,其中sigterm与sigint尤其有一点区别比较重要,但大都没有提及,今天我就遇到了这个问题,纠结了20分钟才搞明白咋回事。

首先,对于说这几个信号都是终止程序运行的说法不太准确,因为程序收到信号后,如果不对信号处理,就会导致程序退出,但如果程序捕获信号进行处理,按照它的逻辑,它是不一定会退出的。

在这三个信号中,sigkill是不能被捕获的,程序收到这个信号后,一定会退出。这就是kill -9一定能保证将程序杀死的原因。

下面说一下sigterm与sigint的区别,其中有一点区别区别很多文章都没有提及,也是我写这篇blog的原因(如果人家都写了,我就不用写了呗)

信号 产生方式 对进程的影响
sigint 通过ctrl+c将会对当进程发送此信号 信号被当前进程树接收到,也就是说,不仅当前进程会收到信号,它的子进程也会收到
sigterm kill命令不加参数就是发送这个信号 只有当前进程收到信号,子进程不会收到。如果当前进程被kill了,那么它的子进程的父进程将会是init,也就是pid为1的进程

下面这两个代码片段就能够验证这种情况(注意使用pcntl的时候,一定要declare ticks,要不然会杯具的发现函数没有被调用,进程不退出,信号发过去没有作用。php手册竟然没有强调这一点):

文件:loadhelper.php

#为了pcntl能够截获信号
declare(ticks = 1);

$arr_processes = array();

function terminate($signo){
    echo "aaaaaaaaaaa\n";
}

pcntl_signal(SIGTERM, "terminate", true);
pcntl_signal(SIGINT, "terminate", true);

foreach($argv as $key => $operation){

    if(0 === $key){
        continue;
    }   

    $pipes = array();
    $process = proc_open($operation, array(), &$pipes);
    if(false === $process){
        exit(-1);
    }
    $arr_processes[] = $process;
}

while(true){
    sleep(100);
}

文件:child.php

declare(ticks=1);

pcntl_signal(SIGINT, "terminate");
pcntl_signal(SIGTERM, "terminate");

function terminate($signo){
    echo "test_child\n";
}

while(true){
    sleep(100);
}

使用命令php loadhelper.php “php test.php”可以启动这个测试。
1.输入ctrl+c发送sigint可以看到,父进程与子进程的terminate都得到了执行,都有输出,但父进程不会退出,因为子进程还没有退出
2.通过kill向父进程的pid发送sigterm,可以看到,只有父进程输出

遗留问题:

父进程(loadhelper)接受到一次信号后,如果在terminate函数中调用exit,它还是不能退出的,因为还有子进程没有退出。但是从此以后它就不能再接收信号了(子进程还是能够接收到sigint),可能是exit使进程进入了待回收状态,具体还 需要后续在分析一把。

---------------------------------------------------------------
本站作品根据创作共同协议进行授权, 转载时请务必以超链接形式标明文章原始出处
原文地址:http://www.mirecle.com/2010/05/20/sigterm-sigint-sigkill-difference.html
---------------------------------------------------------------

分类: 程序员 标签: ,

php中getopt的缺陷及修复

2010年5月17日 1 条评论

在这里,我不得不再一次感叹php语言库函数的山寨与不专业。getopt函数就是一个典型的例子,通常用的时候,大家可能觉得没有什么,但在某些情况 下,就真的让人很囧。一个简单的函数,稍微多花几分钟就弄得更好一些了,但这个语言有个随意的开端,就有个随意的实现啊。

在linux中,使用getopt时候,有两种情况:

1.取得的参数解析成字符串:“php test_arg.php -c abc”,这种情况c参数取得的结果就是abc这个字符串

2.取得的参数解析成数组:“php test_arg.php -c abc -c abc123”,这种情况c参数取得的结果就是包含abc与abc123的数组

但是遇到这种情况呢:“php test_arg.php -c abc*”?由于linux的shell已经帮程序做了输入参数的解析,这时候c参数得到的既不是abc*这个结果也不是一个数组,而是被shell展开成了很多文件名后的第一个。

可能getopt用的童鞋很少,但这种山寨的设计,实在太让人憋屈了,自己花个10分钟写一个就比它的要好,为了避免大家重复劳动,分享一个代码片段

   function mygetopt(){
        global $argv;
        $result = array();

        $current_key = false;
        foreach($argv as $opt){

            $matches = array();
            if(1 === preg_match("/^-{1,2}(.*)$/", $opt, $matches)){
                $current_key = $matches[1];

                if(false === isset($result[$current_key])){
                    $result[$current_key] = false;
                }
            }else if (false !== $current_key){

                if(false === $result[$current_key]){
                    $result[$current_key] = $opt;
                }else{
                    if(false === is_array($result[$current_key])){
                        $result[$current_key] = array($result[$current_key]);
                    }
                    $result[$current_key][] = $opt;
                }
            }
        }   

        return $result;
    }

为了方便使用,将新版本的getopt函数设置为不接受任何参数,但是解析的结果可以输出所有的参数内容。因为php官方的getopt函数使用后,也无非是对输出的数组进行foreach之后进行switch,还不如方便点,直接解析所有呢。除了这一点,这个getopt函数的输出结果与php官方的完全一致

php官方getopt函数参考文档:http://cn.php.net/manual/en/function.getopt.php

---------------------------------------------------------------
本站作品根据创作共同协议进行授权, 转载时请务必以超链接形式标明文章原始出处
原文地址:http://www.mirecle.com/2010/05/17/php-and-repair-defects-in-the-getopt.html
---------------------------------------------------------------

分类: 程序员 标签: , ,

php中&符号的滥用与它引发的bug

2010年5月7日 1 条评论

php中,使用&表明这个引用是指针,这样在两个引用可以指向同一个内存空间。但其实不使用&的情况下,php也是写时拷贝的,zend引擎只有在修改的时候才会发生内存拷贝,不修改的话是不会产生消耗的。在实际使用中,我还发现使用&符号反而性能会降低。

在不需要修改的情况下,建议尽量不要使用&符号,否则不仅降低效率,还有可能造成出现bug。今天查看最近对测试框架的升级,就踩上了simpletest上面的一个bug,请看simpletest中,想testsuit加上case的函数:

function addTestCase(&$test_case) {
     $this->_test_cases[] = &$test_case;
}

这么简单的函数,我想大家一般都会认为没有问题吧,正常情况下它都能很好的工作,但是如果你这样用,就bug了:

foreach($arr_cases as $case){
     $this->test_suit->addTestCaseOpenTest($case);
}

你会发现_test_cases这个数组里面,只哟foreach最终的那个元素,因为函数都是接受的值引用,foreach改变$case的值,就把已经传入_test_cases数组的内容都给改写了,于是就悲剧了。对于simpletest来说,它并不需要修改用户的case程序,这样做值引用显然是多此一举,还产生了bug。

关于性能降低,用一个简单的代码测试一下就知道了

$a = array('a','c','n'); 

function printArray(&$arr)
{
    print(count($arr));
}

for($i=0;$i<100000;$i++){
    printArray($a);
}

用time命令跑一次,把printArray的&符号去掉再跑一次,可以看到大致下面的结果(机器不同,结果不同啊)

带有&符号 不带有&符号
real    0m0.183s
user    0m0.130s
sys     0m0.053s
real    0m0.160s
user    0m0.101s
sys     0m0.060s

可见使用&反而会使性能下降的,所以除非有必要,不建议使用&符号

---------------------------------------------------------------
本站作品根据创作共同协议进行授权, 转载时请务必以超链接形式标明文章原始出处
原文地址:http://www.mirecle.com/2010/05/07/php-in-the-ampersand-on-the-abuse-of.html
---------------------------------------------------------------

分类: 程序员 标签:

paxos算法解决单点问题与资源定位

2010年4月29日 没有评论

今天早茶的topic。介绍了paxos算法与zookeeper相关的内容,可以解决单点问题觉得还挺实用的。这个算法由三个不同类型的实体,通过投票的方式决策出一个值传播到网络中,实现分布式数据的统一,使各个节点不会各自为政。

paxos是一种比较主流的算法,google与微软的集群都用这个,具体参与进来的有三个实体:

1.提议者:提议者发起新的提议,比如设置某个值。每个提议都有个编号。提议者根据参与者的反馈,多数参与者赞同的提议就获得通过。

2.参与者:参与者对提议者的提议进行投票,将投票结果反馈给提议者。当有多个提议时,参与者倾向于接受编号大的提议。例如已经接受编号n的,此时收到了编号为n-1的提议,就会拒绝

3.接受者:接受提议者与参与者的决策(获得投票通过的提议)。

一个典型的也是最简单的流程:

 Client   Proposer      Acceptor     Learner
   |         |          |  |  |       |  |
   X-------->|          |  |  |       |  |  Request
   |         X--------->|->|->|       |  |  Prepare(N)
   |         |<---------X--X--X       |  |  Promise(N,{Va,Vb,Vc})
   |         X--------->|->|->|       |  |  Accept!(N,Vn)
   |         |<---------X--X--X------>|->|  Accepted(N,Vn)
   |<---------------------------------X--X  Response
   |         |          |  |  |       |  |

如图,为了简单理解,可以认为proposer与acceptor是相同功能server构成的一个集群,client可以认为是一个外部的用户,发送一个请求到集群后,集群中的一个server扮演提议者角色发起一个提议,后面的三个accepto进行投票,投票反馈给提议者后发现获得通过,acceptor将信息扩散给接受者。这样整个集群中就针对这个提议达成了一致。

根据这个算法,接受者收到的信息是顺序的,不会产生乱序的问题。所以对于需要序列化的服务,就可以使用这种方式将单点整成多点,避免运维风险。

还有一些更复杂情况以及一个极端情况请见参考资料吧,另外:

1.集群中有多少个节点,首先就是各个节点就是要知道的。集群中要想增加一个新的节点比较麻烦

2.当集群中有效的节点数是少数时,算法会失效

zookeeper是用来协调分布式应用的,用于维护资源信息,它的关键算法就是用的paxos来做的。当然,在其上也有一些更复杂的内容。提供服务的节点作为client链接到zookeeper上面,与zookeeper保持心跳。当client宕机,zookeeper中的一个服务节点发现后就会通过投票流程来判定这个client挂掉了,其它依赖于这个client的服务作为算法中的接受者,收到挂掉的信息后,将依赖改到其它的client上面去。当然,也存在client断开zookeeper中的一个节点后连到zookeeper的另外一个节点,但因为算法保证了发送给client断开与联通消息的顺序,也是可以满足需求的。

在我看来,zookeeper的最大作用是使资源配置服务器本身从单点变为多点,避免了单点运维的问题。对于paxos算法还是很不错的,对于需要将系统中需要将命令序列化,而又希望避免服务单点是一个非常有效的方法。

参考资料:
1.Paxos algorithm
2.zookeeper

---------------------------------------------------------------
本站作品根据创作共同协议进行授权, 转载时请务必以超链接形式标明文章原始出处
原文地址:http://www.mirecle.com/2010/04/29/paxos-algorithm-to-solve-the-problem-and-the-resources-to-locate-a-single-point.html
---------------------------------------------------------------

分类: 程序员 标签: