单元测试PHPUnit入门三板斧

什么,你是程序员?什么你从来没写过单元测试用例?嗯,不要惊讶,这在国内正常的啦。有的觉得写这个玩意太耗时间了,有的干脆就不知道单元测试用例是怎么玩的。说来惭愧,小马也是在CICD的“胁迫”下开始正式涉足。

啥是单元测试

百度百科是这么说的:

单元测试(unit testing),是指对软件中的最小可测试单元进行检查和验证。对于单元测试中单元的含义,一般来说,要根据实际情况去判定其具体含义,如C语言中单元指一个函数,Java里单元指一个类,图形化的软件中可以指一个窗口或一个菜单等。总的来说,单元就是人为规定的最小的被测功能模块。单元测试是在软件开发过程中要进行的最低级别的测试活动,软件的独立单元将在与程序的其他部分相隔离的情况下进行测试。

还别说,说得还挺在理。注意这里的人为规定的最小可测单位,意思是说其实不同情况下可测单元是人为规定没有统一规范的。也就是,如果是一个框架的控制器class,对它来写单元测试的话,打桩和mock的东西就会非常多,这种的通常情况下就不适合做单元测试,要做的单元测试一般是单一职责的class或者函数。

小马就以PHP来展开吧。PHP单元测试框架也比较多,下面就拿比较主流的PHPUnit来起飞吧。

第一斧:PHPunit安装

要使用PHPunit,首先肯定是安装,安装有两种比较简单的方式:php档案包(phar)和composer。小马就使用composer安装的PHPunit,安装过程还是比较简单的。小马在安装方面之前已经有相关文章了,这里就不再赘述了,可以参看文章《单元测试PHPUnit初体验之安装与示例》

第二斧:IDE配置支持PHPunit

因为我们基于IDE开发PHP项目,于是就想也基于IDE直接运行我们的测试用例,所以才有了这一板斧。意思是对IDE配置完之后,我们可以不用到命令行窗口执行php phpunit.phar 或phpunit命令来运行测试用例class,而是直接使用IDE提供的菜单点击run即可运行用例,十元一个非常甜非常甜,啊,不是,非常方便。下面我们就以PHPstorm为例来讨论下怎么配置IDE支持单元测试。

在讨论配置之前,我们必须先来统一下共识。phpunit框架编写的测试用例class执行方式有两种:

1、命令行窗口执行

cmd下用已全局安装的命令(PHPunit或php phpunit.phar)到测试文件目录下直接执行测试class文件即可(命令执行等同于自动加载了测试框架)。

2、用IDE支持直接右键run运行测试class文件

前提是IDE要配置自动加载测试框架的代码才可以直接run,可以理解为直接run的话需要加载一下测试框架才能跑起来测试框架代码。

好了,如果以上看不懂不要紧,我们继续往下看具体是如何配置的,或许会柳暗花明呢。

打开phpstorm,file->settings->Languages & Frameworks->PHP,我们配置我们的PHP版本;然后进入PHP->Debug->Test Frameworks配置我们的 PHPUnit Lib。这个一点注意了,这里三种方式。我们先选第二种path to phpunit.phar,然后底下自然要选我们的安装目录下的phpunit.phar文件了,然后发现并没有phpunit.phar文件,只有phpunit和phpunit.bat。这就奇怪了,难道composer安装方式没有phpunit.phar文件吗?不管了,先下载一个phpunit.phar配置进去看看。于是跑起来,嘿嘿,果然想得美,报错了。

小马立马去下载了对应版本的phpunit.phar文件(版本对应表各版本文件下载),再跑一下看看。

此时不报版本问题了,而是报的测试框架类找不到。是不是第二种path to phpunit.phar的方式不好使呢?小马也没有去深究,直接换成第一种自动加载的方式use Composer autoloader。于是这个时候自然是要配置到我们安装目录下的自动加载文件\vendor\autoload.php。如下。

然后我们右键执行一下class文件,这一步超爽。

这里被测函数代码是return Hello

哇塞,我们看到运行成功的结果了!也就是说直接IDE的run支持必须在配置那里配置自动加载框架,否则run会报错找不到测试框架class,在用例里写自动加载代码也run不了!有机灵鬼的同学说了,如果此时我就是不想用配置自动加载的方式呢?行,那就不要用IDE直接run了,自己去cmd跑phpunit命令也可以(其实跑命令等同于加载了框架)。值得一提的是,cmd直接运行是没进入被测项目框架的(或者是因为原框架自动加载在cli下不被支持导致),原本项目 class如有依赖的类文件要在用例中重新自行包含。

总结:如果我们配置了自动加载框架文件,就直接run吧,不用再去命令行了。当然要是想直接取命令行执行也行,其实效果是一样的,命令相当于自动加载,只是有些未知问题要注意下即可。

第三斧:写单元测试用例

上面我们其实先介绍了配置,但其实我们跑了一个用例,我们还没介绍。接下来来探讨下用例该怎么写。

写测试用例其实还依赖于被测代码的可测性如何写可测性代码),如果被测代码类之间的耦合比较高,那单元测试用例写起来也是相当头疼,所以,单元测试不仅是保证代码质量其实还从侧面降低了代码的耦合度。

如果是测试驱动型开发过程,那可能就是先写单元测试用例再写功能代码呢。写功能代码的时候,你就会考虑这样写是否可以比较方便地mock,是不是输入和输出都是可控的,每个单元是不是单一职责。

比如控制反转就是一种简单却又非常有用的解耦代码技巧,特别适合单元测试。毕竟,保持松散耦合对于能够彼此独立地分析各个单元至关重要。IoC的关键点是将控制代码(when to do something)与执行代码分开(what to do when things happen)。该技术提高了程序的灵活性,使我们的代码更加模块化,并减少了组件之间的耦合。关于怎么写出可测性代码这里就不赘述了,我们还是回到正题,看下测试用例该怎么写,关于测试框架的语法教程请先参看官方文档。来看一个例子。

我们先来看一个需要被测试的功能代码:

注意了,我们来写对于上面这个class的方法的测试用例。在我们的项目目录下新建一个目录Testcase,并新建class文件CommonLibCommonTest.php,编写测试方法testFunctionTest。这里class的Test和方法的test是规范,需要注意一下。

注意文件头的处理,这里IDE配置了自动加载可以不用加载自动加载文件就可以,但如果没有在IDE中执行呢?自然,命名执行相当于加载可以不用,但是其他方式执行呢?是不是就是要保证加载框架了?这个点留给观者自行思考。另外,如果框架载入不用use命名空间,像代码中注释的直接继承框架中的类名PHPUnit_Framework_TestCase也是可行的。

这例子用了两种断言和数据供给器

然后我们来run一下:

OK,测试执行成功了!

最后不得不提醒的是,如果包含进来的被测class文件是有定义命名空间的,在测试用例中调用必须带上命名空间,否则无法找到类,如new \CommonLib\Common()。另外,如果测试用例中new的一个实例本身有继承父类,且有定义了命名空间,则这个父类将不被找到(这个也就是为什么这种本身有继承父类的class不建议来写单元测试用例)。

单元测试PHPunit入门三板斧就到这了,本文只是入门,很多复杂的待一起进步,比如我们要测试DB要怎么写用例呢?虽然这里只是入门但是大差不差,循序渐进即可。具体的测试用例编写框架语法还是建议通读一下官方教程。谢谢品阅,欢迎指点。

单元测试案例相关可参考:

案例1

案例2

案例3

案例4

案例5

原创文章,未经允许请勿转载。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,245评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,749评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,960评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,575评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,668评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,670评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,664评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,422评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,864评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,178评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,340评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,015评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,646评论 3 323
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,265评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,494评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,261评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,206评论 2 352