目录php
v1.0
html
做者:ZBW、ZGJlaravel
PHP应用大多应用的单元测试框架是PHPUnit,这一框架也被Laravel集成了进来,而且Laravel增添了一些额外的功能以方便开发者进行Web相关的测试。本文将以项目中应用的单元测试为基础,介绍Laravel下PHPUnit的相关内容。web
注意到本文以Laravel 5.1为基础,可能部分API在后续版本中有变更,但总体的使用方法变更不大。数据库
经过composer配置composer.json中的依赖,并使用composer install
来安装phpunit,安装后的二进制文件在/vendor/bin/下。json
(也可尝试使用apt install phpunit
来安装phpunit)bootstrap
Laravel默认自带了名为phpunit.xml
的配置文件,该文件已经为咱们配置好了phpunit自己。api
项目使用的配置文件以下:数组
<?xml version="1.0" encoding="UTF-8"?> <phpunit backupGlobals="false" backupStaticAttributes="false" bootstrap="bootstrap/autoload.php" colors="true" convertErrorsToExceptions="true" convertNoticesToExceptions="true" convertWarningsToExceptions="true" processIsolation="false" stopOnFailure="false"> <testsuites> <testsuite name="Application Test Suite"> <directory>./tests/</directory> </testsuite> </testsuites> <filter> <whitelist> <directory suffix=".php">app/</directory> </whitelist> </filter> <php> <env name="APP_ENV" value="testing"/> <env name="CACHE_DRIVER" value="array"/> <env name="SESSION_DRIVER" value="array"/> <env name="QUEUE_DRIVER" value="sync"/> </php> <logging> <log type="coverage-html" target="./tests/codeCoverage" charset="UTF-8"/> </logging> </phpunit>
其中须要注意如下内容:浏览器
<filter>:该部分定义了phpunit可访问的路径,以上配置中咱们只测试app文件夹下的内容。
基于以上内容,一个方便浏览测试报告的方式是,将tests/codeCoverage文件夹下的报告入口html文档软连接至public文件夹下,从而能够由浏览器直接访问:
ln -s tests/codeCoverage public/tests
从而浏览器访问路由:/tests便可看到测试报告。
规范的方法是使用artisan新建测试样例:
php artisan make:test xxxTest
该命令会在tests文件夹下新建一个xxxTest.php,其中包含了一个默认测试函数。
在这部份内容中咱们主要须要应用断言来检查函数的输入和输出是否匹配。断言是phpunit自己就带有的功能。
经常使用的一些断言包括:
$this->assertTrue(表达式) //检查表达式是否为真 $this->assertFalse(表达式) //检查表达式是否为假 $this->assertEquals(X,Y) //检查两个变量是否相等 $this->assertFileExists(文件) //检查文件是否存在
具体的断言函数可参考PHPUnit文档
Laravel集成PHPUnit最方便的地方是其能够编写关于Web控制器及功能的测试。
例如测试某个页面访问是否正常的测试内容以下:
public function testIndex() { $this->visit('logout') ; $this->visit('/desexp') ->see("设计性实验") ->see("请选择实验") ->see("D01"); $this->visit('/login') ->see('登陆') ->type($this->gen_admin_email , 'email') ->type($this->gen_admin_password , 'password') ->press('login-submit'); $this->visit('/desexp') ->see("设计性实验") ->see("请选择实验") ->see("D01"); }
这部分测试编写的方式是将全部须要运行的函数按前后顺序串联起来。
一些访问方面的函数以下,这部分函数通常用于测试访问及与页面进行交互。
visit('路由') // 访问某个地址 see('xxx') //检查访问的页面中是否出现了xxx dontSee('xxx') //与see功能相反,检查是否没有出现xxx type('输入内容',输入框name属性) //输入内容至输入框 check('单选框name属性') //选中checkbox select(’内容‘,’下拉菜单区域‘) //选择下拉菜单项 press('xxx') //按下指定元素或按钮 attach('文件路径','文件上传name属性') //附加文件
在上文的例子中,咱们测试前能够选择手动模拟登录操做。
测试JSON API时以上的函数每每起不到做用,此时须要使用以下的函数来向接口发起请求及验证结果。
get/post/put/patch/delete('address',[payloads]) //以以上的HTTP方法请求路由 seeJson([json内容]) //检查返回的json是否包含内容
固然以前的visit
方法能够看做没有额外数据的get
(注意不是无参数,后文会介绍)
一个例子以下,这部分代码经过getTable函数验证了获取html表格内容的正确性。
$_GET['id'] = $this->report_id_pub ; $html_file = Config::get('phylab.experimentViewPath').$this->report_id_pub.".html"; $str_html = file_get_contents($html_file); $this->visit('/getTable') ->seeJson([ 'status' => SUCCESS_MESSAGE , 'contents' => $str_html , ]) ;
此外,还有call('http请求方法','路由',‘数据’...)
这一方法以更灵活的方式向接口发起请求。这一函数将返回Laravel原生的http请求对象。你能够继而经过phpunit的断言验证其中结果。
Laravel增长了一些额外的断言以方便用户检查Web请求的结果。例如:
->assertResponseOk(); //检查返回是否为HTTP 200 ->assertResponseStatus($code); //检查返回是不是指定的状态码 ->assertRedirectedTo($uri, $with = []); //检查是否有重定向
具体能够参考PHPUnit Assertions
在Laravel中部分路由经过中间件来确保安全性,例如不少API以Auth中间件来确保只有登录用户才能使用接口,但在测试中常常登录无疑增长了测试的复杂性,使用session相对来讲也是一种麻烦的办法。
能够在测试类的开头增长以下内容
use WithoutMiddleware;
从而在该测试代码文件中暂时使中间件不产生做用
部分测试的函数须要对数据库进行操做,而测试先后须要保证数据库状态的一致性。手动进行恢复的操做也不现实,好在Laravel内置了一些方法使咱们能方便地进行数据库方面的测试
使用迁移:use DatabaseMigrations;
或使用事务:use DatabaseTransactions;
将以上内容任一个添加在测试类开头,Laravel会替你完成数据库在测试先后的恢复工做
在咱们的项目中,以前的开发者在不少地方定义了一些全局变量,或者能够说是相似于C语言的宏定义。包括Laravel框架自己中也包含了不少这样的宏定义。初次运行测试时咱们遇到的一个很尴尬的问题是:不能有多个测试代码文件,不然phpunit就会报相似于”重复定义“的错误。
一个暂时的解决办法是这样的,在每一个测试类开头添加:
protected $preserveGlobalState = FALSE; protected $runTestInSeparateProcess = TRUE;
这二者意味着每一个测试进程是独立的,且各测试之间的状态不被保留。
前述的一些用于测试的请求方法,其中能够额外附带的数组参数其实是请求附带的payloads,但不少时候咱们要发起相似这样的带参数请求:
http://ip:port/getTable?id=1234567
若是直接在get
方法内设置['id'=>'1234567']
,会发现测试运行中仍是直接请求/getTable
,而没有任何参数
一个解决办法是测试时直接修改PHP的_GET
变量,例如
$_GET['id'] = '1234567' ;
这一办法笔者认为有些简单粗暴,但还没找到更好的方法,还请各位读者多多指教。
运行测试很是简单,只须要在phpunit.xml所在的目录下运行:phpunit
,便可自动运行全部测试。
若是你想运行单个测试文件,能够以以下方式:
phpunit path\to\testFile.php
这将运行该文件中的全部测试函数。
你也能够运行某一个测试函数,但该状况下最好指定该函数所在的文件,以免重名的状况:
phpunit --filter testFunction path\to\testFile.php
在配置部分配置了软连接后,你能够直接进入测试报告的页面
ln -s tests/codeCoverage public/tests
直接访问ip:port/tests后将自动进入测试报告的主页,点击每一个文件夹能够浏览其中内容的测试覆盖率。
测试覆盖率分为三栏,第一栏是覆盖的行数,第二栏是方法数,第三栏是覆盖的类的数量。