【PHP】php逻辑测试,测试也要设计—phpunit实践
概述本文阐述如何利用面向对象的思想,在phpunit框架下实现测试用例、数据文件、配置信息和lib库等信息分离,并能有效组合。
也许有些QA认为,测试代码只要能满足测试要求即可,根本不需要有什么设计的理念。其实不然,好的测试代码,应该是可读性强,可扩展性强。以下分享一个我在实际项目中的小想法来阐述这个观点,仅作抛砖引玉之用。
具体实现在autoFunc测试目录下,创建conf、data、lib三个目录,分别用于保存配置信息、数据文件和lib库,测试用例直接放在autoFunc下。
A 方案直接在test_object_put_get.php中require config.php和util.php,如下:
require_once 'conf/config.php';
require_once 'lib/util.php';
似乎很简单,但这里却有两个问题,phpunit的测试用例,是以class继承PHPUnit_Framework_Testcase类的方式来组织的,这样在testcase中就无法访问config.php的变量列表,或许你会说,这个很好解决呀,直接的testcase的class中指定config.php的变量名为global类型即可,如下:
弊端1:config.php中有几个配置,testcase中就需要global几个,不免太手工了。
弊端2:util.php中function无法通过global方式声明,在testcase中也就无法访问到。
B 方案鉴于A 方案的局限性,我提出了面向对象的方式,来实现配置信息、测试用例、lib库有效的隔离。B 方案最突出的地方在于引入了继承的概念,容我一一道来。
config.php测试用例中总有一些常量会被反复使用到,使用配置文件的方式是所有测试人员的共识,在这里,我做了一个小小改善,将config信息包装为类的方式,以便于在lib库的类中使用到,如下:
class Config{
public $WEB_SITE = "http://test.com:8090/";
public $BUCKET = "vincent";
public $ACCESS_KEY = "jhPLaYVh11wo";
public $SECURE_KEY = "A23mtEjHwv1z";
public $SIGN_FLAG="TST";
public $DATA_DIR = "./data/";
//no use now
public $IP = "";
public $TIME = "";
}
util.php编写测试用例时,总会有一些逻辑处理片段反复的出现,这造成了测试代码的大量冗余,也加大了维护成功,将这些逻辑处理封装为一个个函数是第一个步,之后将通用的函数抽取为lib库的形式,而那些函数适合抽取为lib库。根据经验我列举几个lib的共有特性:
1.与测试用例逻辑无关
2.完成单一职责
3.可被其他用例共用
如果满足这三个条件,那这个函数就可以抽取为lib库,如下文的signature签名函数。
在实际项目中,我抽取了部分函数为lib库,并将lib库也封装为类的形式,同时继承于class Config,如下:
require_once 'conf/config.php';
class Util extends Config{
/**
* 返回签名串
* @param string $method
* @param string $object
*/
public function signature($method, $object){
$content = "$this->SIGN_FLAG\nMethod=$method\nBucket=$this->BUCKET\nObject=$object\n";
if($this->IP != ""){
$content .= "Ip=".$this->IP."\n";
}
if($this->TIME != ""){
$content .= "Time=".$this->TIME."\n";
}
$sign = "?Sign=$this->SIGN_FLAG:$this->ACCESS_KEY";
return $sign;
}
}
注意:这里Util类继承于Config类,也就继承了Config类中的所有成员变量,故在Util类中可以直接通过$this指针直接访问到配置信息。
TEST CASEStestcases中通过在setUp()函数中new一个Util对象,这样就可以轻松使用lib库中所有方法了,如下:
require_once 'PHPUnit/Framework.php';
require_once 'lib/util.php';
class ObjectPutGET extends PHPUnit_Framework_Testcase{
protected $util;
protected function setUp(){
$this->util = new Util();
}
public function testNormal(){
$object = '/normalObj';
$sign = $this->util->signature("PUT", $object);
$url = $this->util->WEB_SITE.$this->util->BUCKET.$object.$sign;
$http = curl_init();
$infile = fopen("data/file1", "r");
curl_setopt($http, CURLOPT_URL, $url);
curl_setopt($http, CURLOPT_INFILE, $infile);
curl_setopt($http, CURLOPT_INFILESIZE, 8);
curl_setopt($http, CURLOPT_UPLOAD, 1);
curl_exec($http);
curl_close($http);
fclose($infile);
}
}
这里testcases中有一个protect的成员变量$util,并在setUp()中初始化,这样在每个testcase中都可以使用$this->util来访问Util类中的所有方法和变量了。
问题:测试中可能遇到这样的问题,lib库的function依赖于config中的配置,在测试用例中调用function时,又希望能用不同的参数。
解决:按照gtest的测试经验,需要为function提供额外的参数,供传入不同的值。既然使用面向对象了,这里就简单了,只需要通过实例化的lib库调用$this->util->配置项,直接更改配置项信息。如果希望封装好点,可以设置get、set方法分别用于配置项的get和set。
数据驱动将测试数据保存到data/目录下的相应文件中,通过php unit的dataprovider机制与测试代码结合,将测试数据与用例逻辑解耦合,增加case只需要相应增减数据文件,不需要变更用例逻辑,降低维护成本,提高可扩展性。
/**
* dataprovider for testObjectFileType
*/
public function fileType(){
return array(
array("fputtype.txt", "/putfiletype.txt"),
array("fputtype.docx", "/putfiletype.docx"),
array("fputtype.pdf", "/putfiletype.pdf"),
array("fputtype.xls", "/putfiletype.xls"),
array("fputtype.mp3", "/putfiletype.mp3"),
array("fputtype.mkv", "/putfiletype.mkv"),
array("fputtype.rar", "/putfiletype.rar")
);
}
/**
* 文件,文件类型为txt word excel pdf mp3 mkv rar
* @dataProvider fileType
*/
public function testObjectFileType($fileType, $object_name){
$fileName = $this->util->DATA_DIR.$fileType;
$obj = $object_name;
//put object
$result = $this->util->putObject($fileName, $obj);
$this->assertEquals("", $result);
//get object
$result = $this->util->getObject($obj);
//check
$expect = md5(file_get_contents($fileName));
$actual = md5($result);
$header = new Header(file_get_contents($this->util->HEADER_FILE));
$etag = $header->getETag();
$this->assertEquals($expect, $actual);
$this->assertEquals($expect, $etag);
}
这样组织后,测试用例、配置信息、数据文件以及lib库就解耦了,不管修改哪部分,都可以直接找到并修改,不用担心会对其他case造成什么影响。
A. 编写测试用例,在测试用例根目录下找到对应测试文件,增减相应的case逻辑即可,并且可以在测试用例中轻松调用lib库,动态修改配置信息。
B. 修改数据文件?两步即可,在data目录下增减数据文件,修改对应测试用例的数据驱动信息。
C. 在conf目录中修改配置信息,由于配置信息是全局的,修改已有配置信息需要慎重。
D. lib库与conf一样是全局可见的,修改已有function需要考量对其他case有没有影响。
总结不仅仅RD的代码需要可扩展性,QA的测试代码同样也需要。
测试也需要设计。
猜你喜欢
- 【PHP】详解ThinkPHP5实现极验滑动验证码geetest功能
- 下面由thinkphp教程栏目给大家详解ThinkPHP5实现极验滑动验证码geetest功能,希望对需要的朋友有所帮助!ThinkPHP5实现极验滑动验证码geetest功能现在很多网站,比如淘宝,京东等都改用使用极验拖动验证码实现登录,这种方式比传统的验证码方式有更好的体验,减少用户输入的错误,也同样能起到防盗刷的功能。现在很多极验都是第三方的,也很多都是收费的。这里主要介绍thinkphp整合系列之极验滑动验证码geetest,官网:http://www.geetest.com具
- 【PHP】php判断字符串是否是中文
- 可以判断。判断方法:1、使用preg_match()函数配合正则来判断是否全是中文 ,语法“!preg_match("/[^\x80-\xff]/i",$str)”;2、使用preg_match()函数配合正则来判断是否包含中文 ,语法“preg_match("/[\x7f-\xff]/", $str)”或“preg_match('/[^\x00-\x80]/',$str)”。本教程操作环境:windows7系统、PHP8.1版、
- 【PHP】中文日文字符串校验解决方案
- 由于开发需要,要识别中文和日文文字段落,网上查了很多资料,大部分都是使用正则校验preg_match,但中文和日文有些汉字是相同的,不能直接校验出结果,经过多次修改,也算是找出了解决办法。首先找到中文和日文的正则校验中文校验:preg_match('/\p{Han}+/u','',$str);日文校验:preg_match('/[\x{4E00}-\x{9FBF}\x{3040}-\x{309F}\x{30A0}-\x{30FF}]/u',&nbs
- 【PHP】PHP8.1 Fiber交叉执行多任务
- span style="text-wrap: wrap;">大家的电脑应该都是大等于2核的了,但是大家电脑上同时运行的程序大多远远多于cpu的核心数量。这是因为操作系统在任务处理上采取了宏观上并行,微观上串行的做法。也就是cpu每个程序都执行了一点点时间然后就切换去执行别的程序。使得大家看上去都执行了很多。现在 php8.1 。推出了 fiber 。把调度权利赋予给了各位 php 开发。那么我们有 fiber 我们可以实现什么样的新操作呢。(本文给大家抛个砖,欢迎大家补充更有意思的使用)</span
- 【PHP】thinkphp利用缓存提高数据库查询性能
- ThinkPHP是一款十分受欢迎的PHP框架,它提供了许多便捷的功能和优化的设计,使得开发者可以更高效地进行Web应用程序的开发。其中,利用缓存提高数据库查询性能是一个常见的优化手段。本文将分享一些关于如何在ThinkPHP中利用缓存提高数据库查询性能的经验。一、什么是缓存?缓存是指将经常查询的数据存储在快速访问的存储介质中,以提高数据的访问速度。在Web应用程序中,数据库是最常用的数据存储介质之一。而经常查询数据库会带来一定的性能压力。因此,利用缓存可以避免频繁地查询数据库,从而提高
- 【PHP】PHP8中如何使用Stringable Interface更方便地处理字符串操作
- PHP8中如何使用Stringable Interface更方便地处理字符串操作?PHP8是PHP语言的最新版本,带来了许多新特性和改进。其中一项令开发者欢欣鼓舞的改进之一就是Stringable Interface的加入。Stringable Interface是一个用于处理字符串操作的接口,它提供了一种更方便的方式来处理和操作字符串。本文将详细介绍如何使用Stringable Interface来提升字符串操作的便捷性,并提供具体的代码示例。首先,让我们了解一下Stringable Inte
- 【PHP】关于PHP8中match新语句的骚操作
- PHP8新语法:match [更骚的匿名函数操作]PHP8 新出的一个语法很好用,就是 match 语句。match 语句跟原来的 switch 类似,不过比 switch 更加的严格和方便原来的 switch 语句代码如下:function getStr( $strType ){ switch( $strType ){ &nb
- 【PHP】php使用curl常见出错
- hp是一款广泛应用于服务器端开发的编程语言。在常见的web应用程序中,php常使用curl库实现http请求,主要用于与其他web服务进行通信。然而,在使用curl时,开发人员可能会遇到各种问题,其中最常见的问题是curl在发送请求时出错。cURL错误通常会导致请求无法正常发送或无法成功获取响应。本文将介绍cURL的常见错误以及如何解决这些问题。一、未安装cURL扩展在使用cURL前,首先需要在PHP中安装cURL扩展,否则cURL库将无法正常工作,在发送请求时会抛出错误。要检查PHP是否已经
- 【C#】C# Winform 文本面板带滚动条
- 【CSS】在H5开发中常见的position属性的应用场景
- 【Python】一种迅速了解pandas版本号的方法
- 【Go】Gotk3简介
- 【MySQL】MySQL 之 视图、触发器、存储过程、函数、事物与数据库锁
- 【JavaScript】JS复制剪切神器clipboard.js基本使用
- 【前端】PHP、Vue和React:如何选择最适合的前端框架?
- 【UniApp】移动框架对比:uniapp和flutter选哪个好
- 【JavaScript】如何从 JavaScript 数组中删除重复元素?
- 【MySql】mysql | mysql5.7升级8.0注意事项