PHPUnit中使用 Laravel怎么实现单元测试
本篇文章为大家展示了PHPUnit中使用 Laravel怎么实现单元测试,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。
1. 数据供给器
用来提供参数和结果,使用 @dataProvider
标注来指定使用哪个数据供给器方法。例如检测app升级数据是否符合预期,addProviderAppUpdateData()提供测试的参数和结果。testAppUpdateData()检测appUpdateData()返回的结果是否和给定的预期结果相等,即如果$appId='apple_3.3.2_117'
, $result=['status' => 0, 'isIOS' => false]
, 则$data中如果含有['status' => 0, 'isIOS' => false]
, 则断言成功。建议在数据提供器,逐个用字符串键名对其命名,这样在断言失败的时候将输出失败的名称,更容易定位问题
。
示例代码:
<?php namespaceTests\Unit; useApp\Services\ClientService; useTests\TestCase; classClientServiceTestextendsTestCase { /** *@dataProvideraddProviderAppUpdateData * *@param$appId *@param$result */ publicfunctiontestAppUpdateData($appId,$result) { $data=(newClientService($appId))->appUpdateData(); $this->assertTrue(count(array_intersect_assoc($data,$result))==count($result)); } publicfunctionaddProviderAppUpdateData() { return[ 'null'=>[null,['status'=>0,'isIOS'=>false,'latest_version'=>'V']], 'errorappid'=>['sdas123123',['status'=>0,'isIOS'=>false,'latest_version'=>'V']], 'androidforceupdate'=>['bx7_3.3.5_120',['status'=>0,'isIOS'=>false]], 'iosforceupdate'=>['apple_3.3.2_117',['status'=>1,'isIOS'=>true]], 'androidsoftupdate'=>['sanxing_3.3.2_117',['status'=>2,'isIOS'=>false]], 'iossoftupdate'=>['apple_3.3.3_118',['status'=>2,'isIOS'=>true]], 'androidnormal'=>['fhqd_3.3.6_121',['status'=>1,'isIOS'=>false]], 'iosnormal'=>['apple_3.3.5_120',['status'=>1,'isIOS'=>true]], 'h6'=>['h6_3.3.3',['status'=>1,'isIOS'=>false]] ]; } }
断言成功结果:
2. 断言方法
常用有assertTrue(), assertFalse(), assertNull(), assertEquals(), assertThat()。
assertThat()自定义断言。常用的约束有isNull()、isTrue()、isFalse()、isInstanceOf();常用的组合约束logicalOr()、logicalAnd()
。例如检测返回的结果是否是null或ApiApp类。
示例代码:
<?php namespaceTests\Unit; useApp\Models\ApiApp; useApp\Services\SystemConfigService; useTests\TestCase; classSystemConfigServiceTestextendsTestCase { /** *@dataProvideradditionProviderGetLatestUpdateAppApi * *@param$appType */ publicfunctiontestGetLatestUpdateAppApi($appType) { $result=SystemConfigService::getLatestUpdateAppApi($appType); $this->assertThat($result,$this->logicalOr($this->isNull(),$this->isInstanceOf(ApiApp::class))); } publicfunctionadditionProviderGetLatestUpdateAppApi() { return[ 'apple'=>[1], 'android'=>[2], 'null'=>[9999] ]; } }
断言成功结果:
3. 对异常进行测试
使用expectExceptionCode()
对错误码进行检测,不建议对错误信息文案进行检测。例如检测设备被锁后是否抛出3026错误码。
示例代码:
<?php namespaceTests\Unit; useApp\Services\UserSecurityService; useIlluminate\Support\Facades\Cache; useTests\TestCase; classUserSecurityServiceTestextendsTestCase { publicstatic$userId=4; /** *设备锁检测 *@throws\App\Exceptions\UserException */ publicfunctiontestDeviceCheckLock() { $this->expectExceptionCode(3026); Cache::put('device-login-error-account-','1,2,3,4,5',300); UserSecurityService::$request=null; UserSecurityService::$udid=null; UserSecurityService::deviceCheck(self::$userId); } }
断言成功结果:
4. 测试私有属性和私有方法使用反射机制
如果只测试私有方法可使用ReflectionMethod()
反射方法,使用setAccessible(true)
设置方法可访问,并使用invokeArgs()或invoke()
调用方法(invokeArgs将参数作为数组传递)。例如检测IP是否在白名单中。
示例代码:
被检测代码:
namespaceApp\Facades\Services; /** *ClassWebDefender */ classWebDefenderServiceextendsBaseService { //ip白名单 private$ipWhiteList=[ '10.*', '172.18.*', '127.0.0.1' ]; /** *ip是否在白名单中 * *@paramstring$ip * *@returnbool */ privatefunctioncheckIPWhiteList($ip) { if(!$this->ipWhiteList||!is_array($this->ipWhiteList)){ returnfalse; } foreach($this->ipWhiteListas$item){ if(preg_match("/{$item}/",$ip)){ returntrue; } } returnfalse; } }
检测方法:
<?php namespaceTests\Unit; useApp\Facades\Services\WebDefenderService; useTests\TestCase; classWebDefenderTestextendsTestCase { /** *测试IP白名单 *@dataProvideradditionProviderIp * *@param$ip *@param$result * *@throws\ReflectionException */ publicfunctiontestIPWhite($ip,$result) { $checkIPWhiteList=new\ReflectionMethod(WebDefenderService::class,'checkIPWhiteList'); $checkIPWhiteList->setAccessible(true); $this->assertEquals($result,$checkIPWhiteList->invokeArgs(newWebDefenderService(),[$ip])); } publicfunctionadditionProviderIp() { return[ '10ip'=>['10.1.1.7',true], '172ip'=>['172.18.2.5',true], '127ip'=>['127.0.0.1',true], '192ip'=>['192.168.0.1',false] ]; } }
测试私有属性可使用ReflectionClass()
, 获取属性用getProperty()
, 设置属性的值用setValue()
, 获取方法用getMethod()
, 设置属性和方法可被访问使用setAccessible(true)
。例如检测白名单路径。
示例代码:
被检测代码:
<?php namespaceApp\Facades\Services; useApp\Exceptions\ExceptionCode; useApp\Exceptions\UserException; useIlluminate\Support\Facades\Cache; /** *CC攻击防御器 *ClassWebDefender */ classWebDefenderServiceextendsBaseService { //路径白名单(正则) private$pathWhiteList=[ //'^auth\/(.*)', ]; privatestatic$request=null; /** *请求路径是否在白名单中 * *@returnbool */ privatefunctioncheckPathWhiteList() { $path=ltrim(self::$request->getPathInfo(),'/'); if(!$path||!$this->pathWhiteList||!is_array($this->pathWhiteList)){ returnfalse; } foreach($this->pathWhiteListas$item){ if(preg_match("/$item/",$path)){ returntrue; } } returnfalse; } }
检测方法:
<?php namespaceTests\Unit; useApp\Facades\Services\WebDefenderService; useIlluminate\Http\Request; useTests\TestCase; classWebDefenderTestextendsTestCase { /** *检测白名单路径 *@dataProvideradditionProviderPathWhiteList * *@param$pathProperty *@param$request *@param$result * *@throws\ReflectionException */ publicfunctiontestCheckPathWhiteList($pathProperty,$request,$result) { $reflectedClass=new\ReflectionClass('App\Facades\Services\WebDefenderService'); $webDefenderService=newWebDefenderService(); $reflectedPathWhiteList=$reflectedClass->getProperty('pathWhiteList'); $reflectedPathWhiteList->setAccessible(true); $reflectedPathWhiteList->setValue($webDefenderService,$pathProperty); $reflectedRequest=$reflectedClass->getProperty('request'); $reflectedRequest->setAccessible(true); $reflectedRequest->setValue($request); $reflectedMethod=$reflectedClass->getMethod('checkPathWhiteList'); $reflectedMethod->setAccessible(true); $this->assertEquals($result,$reflectedMethod->invoke($webDefenderService)); } publicfunctionadditionProviderPathWhiteList() { $allPath=['.*']; $checkPath=['^auth\/(.*)']; $authSendSmsRequest=newRequest([],[],[],[],[],['HTTP_HOST'=>'api.dev.com','REQUEST_URI'=>'/auth/sendSms']); $indexRequest=newRequest([],[],[],[],[],['HTTP_HOST'=>'api.dev.com','REQUEST_URI'=>'/']); $noMatchRequest=newRequest([],[],[],[],[],['HTTP_HOST'=>'api.dev.com','REQUEST_URI'=>'/product/sendSms']); return[ 'index'=>[[],$authSendSmsRequest,false], 'norequest'=>[$allPath,$indexRequest,false], 'allrequest'=>[$allPath,$authSendSmsRequest,true], 'checkauthsms'=>[$checkPath,$authSendSmsRequest,true], 'checkpathnomatch'=>[$checkPath,$noMatchRequest,false] ]; } }
5. 代码覆盖率
使用--coverage-html导出的报告含有类与特质覆盖率、行覆盖率
、函数与方法覆盖率。可查看当前单元测试覆盖的范围。例如输出WebDefenderTest的代码覆盖率到桌面(phpunit tests/unit/WebDefenderTest --coverage-html ~/Desktop/test)
6. 指定代码覆盖率报告要包含哪些文件
在配置文件(phpunit.xml)里设置whitelist中的processUncoveredFilesFromWhitelist=true, 设置目录用<directory>标签,设置文件用<file>标签。例如指定app/Services目录下的所有文件和app/Facades/Services/WebDefenderService.php在报告中。
示例代码:
<?xmlversion="1.0"encoding="UTF-8"?> <phpunitbackupGlobals="false" backupStaticAttributes="false" bootstrap="tests/bootstrap.php" colors="true" convertErrorsToExceptions="true" convertNoticesToExceptions="true" convertWarningsToExceptions="true" processIsolation="false" stopOnFailure="false"> <testsuites> <testsuitename="Unit"> <directorysuffix="Test.php">./tests/Unit</directory> </testsuite> <testsuitename="Feature"> <directorysuffix="Test.php">./tests/Feature</directory> </testsuite> </testsuites> <filter> <whitelistprocessUncoveredFilesFromWhitelist="true"> <directorysuffix=".php">./app/Services</directory> <file>./app/Facades/Services/WebDefenderService.php</file> </whitelist> </filter> <php> <servername="APP_ENV"value="local"/> <servername="BCRYPT_ROUNDS"value="4"/> <servername="CACHE_DRIVER"value="credis"/> <servername="MAIL_DRIVER"value="array"/> <servername="QUEUE_CONNECTION"value="sync"/> <servername="SESSION_DRIVER"value="array"/> <servername="APP_CONFIG_CACHE"value="bootstrap/cache/config.phpunit.php"/> <servername="APP_SERVICES_CACHE"value="bootstrap/cache/services.phpunit.php"/> <servername="APP_PACKAGES_CACHE"value="bootstrap/cache/packages.phpunit.php"/> <servername="APP_ROUTES_CACHE"value="bootstrap/cache/routes.phpunit.php"/> <servername="APP_EVENTS_CACHE"value="bootstrap/cache/events.phpunit.php"/> </php> </phpunit>
上述内容就是PHPUnit中使用 Laravel怎么实现单元测试,你们学到知识或技能了吗?如果还想学到更多技能或者丰富自己的知识储备,欢迎关注恰卡编程网行业资讯频道。