您的当前位置:首页>全部文章>文章详情

【PHP】php逻辑测试,测试也要设计—phpunit实践

CrazyPanda发表于:2024-06-22 17:27:27浏览:258次TAG: #php #测试

概述本文阐述如何利用面向对象的思想,在phpunit框架下实现测试用例、数据文件、配置信息和lib库等信息分离,并能有效组合。

也许有些QA认为,测试代码只要能满足测试要求即可,根本不需要有什么设计的理念。其实不然,好的测试代码,应该是可读性强,可扩展性强。以下分享一个我在实际项目中的小想法来阐述这个观点,仅作抛砖引玉之用。

具体实现在autoFunc测试目录下,创建conf、data、lib三个目录,分别用于保存配置信息、数据文件和lib库,测试用例直接放在autoFunc下。

0795c09576b7458e5dda3f0594116905.png

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类型即可,如下:

7aa835178382461379735e3cbe6b2aa3.png

弊端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具
发表于:2023-12-28 浏览:303 TAG:
【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版、
发表于:2023-12-13 浏览:309 TAG:
【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
发表于:2023-12-14 浏览:386 TAG:
【PHP】PHP8.1 Fiber交叉执行多任务
span style="text-wrap: wrap;">大家的电脑应该都是大等于2核的了,但是大家电脑上同时运行的程序大多远远多于cpu的核心数量。这是因为操作系统在任务处理上采取了宏观上并行,微观上串行的做法。也就是cpu每个程序都执行了一点点时间然后就切换去执行别的程序。使得大家看上去都执行了很多。现在 php8.1 。推出了 fiber 。把调度权利赋予给了各位 php 开发。那么我们有 fiber 我们可以实现什么样的新操作呢。(本文给大家抛个砖,欢迎大家补充更有意思的使用)</span
发表于:2024-01-06 浏览:313 TAG:
【PHP】thinkphp利用缓存提高数据库查询性能
ThinkPHP是一款十分受欢迎的PHP框架,它提供了许多便捷的功能和优化的设计,使得开发者可以更高效地进行Web应用程序的开发。其中,利用缓存提高数据库查询性能是一个常见的优化手段。本文将分享一些关于如何在ThinkPHP中利用缓存提高数据库查询性能的经验。一、什么是缓存?缓存是指将经常查询的数据存储在快速访问的存储介质中,以提高数据的访问速度。在Web应用程序中,数据库是最常用的数据存储介质之一。而经常查询数据库会带来一定的性能压力。因此,利用缓存可以避免频繁地查询数据库,从而提高
发表于:2023-12-08 浏览:424 TAG:
【PHP】PHP8中如何使用Stringable Interface更方便地处理字符串操作
PHP8中如何使用Stringable Interface更方便地处理字符串操作?PHP8是PHP语言的最新版本,带来了许多新特性和改进。其中一项令开发者欢欣鼓舞的改进之一就是Stringable Interface的加入。Stringable Interface是一个用于处理字符串操作的接口,它提供了一种更方便的方式来处理和操作字符串。本文将详细介绍如何使用Stringable Interface来提升字符串操作的便捷性,并提供具体的代码示例。首先,让我们了解一下Stringable Inte
发表于:2023-12-30 浏览:336 TAG:
【PHP】关于PHP8中match新语句的骚操作
PHP8新语法:match [更骚的匿名函数操作]PHP8 新出的一个语法很好用,就是 match 语句。match 语句跟原来的 switch 类似,不过比 switch 更加的严格和方便原来的 switch 语句代码如下:function&nbsp;getStr(&nbsp;$strType&nbsp;){ &nbsp;&nbsp;&nbsp;&nbsp;switch(&nbsp;$strType&nbsp;){ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&amp;nb
发表于:2024-01-06 浏览:317 TAG:
【PHP】php使用curl常见出错
hp是一款广泛应用于服务器端开发的编程语言。在常见的web应用程序中,php常使用curl库实现http请求,主要用于与其他web服务进行通信。然而,在使用curl时,开发人员可能会遇到各种问题,其中最常见的问题是curl在发送请求时出错。cURL错误通常会导致请求无法正常发送或无法成功获取响应。本文将介绍cURL的常见错误以及如何解决这些问题。一、未安装cURL扩展在使用cURL前,首先需要在PHP中安装cURL扩展,否则cURL库将无法正常工作,在发送请求时会抛出错误。要检查PHP是否已经
发表于:2024-03-19 浏览:296 TAG:
【PHP】微服务架构综合实战 一文让你了解什么是微服务 使用PHP 搭建微服务框架 最全微服务架构讲解以及演示
本文将带你从基础的微服务架构设计、网络协议、注册中心、配置中心、网关层面&nbsp;渐进式讲解其微服务。目录一、微服务架构设计方案架构演进微服务概念&nbsp;拆分三个火枪手原则AKF原则二、微服务注册中心和配置中心为什么要使用服务发现与注册为什么要使用配置中心官方下载地址设置环境变量Server配置单机配置集群配置命令解析ThinkPHP接入Consul配置信息中心&amp;nbs
发表于:2024-05-27 浏览:764 TAG:
【PHP】php中几个不常用的函数方法
1.abs():返回一个数的绝对值;2.set_time_limit :设置脚本最大执行时间(如果设置为0则没有时间限制,默认值为30秒,或者是在php.ini的max_execution_time被定义的值,如果此值存在。);3.strip_tags($str,&#39;&lt;p&gt;&lt;a&gt;&#39;):剥去除p和a标签外的字符串中、XML 以及 PHP 的标签;4.iconv():字符串按要求的字符编码来转换;5.is_dir():检查目录是否存在;6.mkdir():创建文
发表于:2024-08-02 浏览:297 TAG: