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]]
];
}
}

断言成功结果:

PHPUnit中使用 Laravel怎么实现单元测试

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]
];
}
}

断言成功结果:

PHPUnit中使用 Laravel怎么实现单元测试

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);
}
}

断言成功结果:

PHPUnit中使用 Laravel怎么实现单元测试

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)

PHPUnit中使用 Laravel怎么实现单元测试

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怎么实现单元测试,你们学到知识或技能了吗?如果还想学到更多技能或者丰富自己的知识储备,欢迎关注恰卡编程网行业资讯频道。

发布于 2021-06-13 23:18:12
收藏
分享
海报
0 条评论
168
上一篇:PHP中怎么实现迭代器模式 下一篇:Java中怎么操作slf4j日志
目录

    0 条评论

    本站已关闭游客评论,请登录或者注册后再评论吧~

    忘记密码?

    图形验证码