1. 數(shù)據(jù)供給器
用來提供參數(shù)和結(jié)果,使用 @dataProvider
標(biāo)注來指定使用哪個(gè)數(shù)據(jù)供給器方法。例如檢測(cè)app升級(jí)數(shù)據(jù)是否符合預(yù)期,addProviderAppUpdateData()提供測(cè)試的參數(shù)和結(jié)果。testAppUpdateData()檢測(cè)appUpdateData()返回的結(jié)果是否和給定的預(yù)期結(jié)果相等,即如果$appId='apple_3.3.2_117'
, $result=['status' => 0, 'isIOS' => false]
, 則$data中如果含有['status' => 0, 'isIOS' => false]
, 則斷言成功。建議在數(shù)據(jù)提供器,逐個(gè)用字符串鍵名對(duì)其命名,這樣在斷言失敗的時(shí)候?qū)⑤敵鍪〉拿Q,更容易定位問題
。
示例代碼:
?php
namespace Tests\Unit;
use App\Services\ClientService;
use Tests\TestCase;
class ClientServiceTest extends TestCase
{
/**
* @dataProvider addProviderAppUpdateData
*
* @param $appId
* @param $result
*/
public function testAppUpdateData($appId, $result)
{
$data = (new ClientService($appId))->appUpdateData();
$this->assertTrue(count(array_intersect_assoc($data, $result)) == count($result));
}
public function addProviderAppUpdateData()
{
return [
'null' => [null, ['status' => 0, 'isIOS' => false, 'latest_version' => 'V']],
'error app id' => ['sdas123123', ['status' => 0, 'isIOS' => false, 'latest_version' => 'V']],
'android force update' => ['bx7_3.3.5_120', ['status' => 0, 'isIOS' => false]],
'ios force update' => ['apple_3.3.2_117', ['status' => 1, 'isIOS' => true]],
'android soft update' => ['sanxing_3.3.2_117', ['status' => 2, 'isIOS' => false]],
'ios soft update' => ['apple_3.3.3_118', ['status' => 2, 'isIOS' => true]],
'android normal' => ['fhqd_3.3.6_121', ['status' => 1, 'isIOS' => false]],
'ios normal' => ['apple_3.3.5_120', ['status' => 1, 'isIOS' => true]],
'h5' => ['h5_3.3.3', ['status' => 1, 'isIOS' => false]]
];
}
}
斷言成功結(jié)果:
2. 斷言方法
常用有assertTrue(), assertFalse(), assertNull(), assertEquals(), assertThat()。
assertThat()自定義斷言。常用的約束有isNull()、isTrue()、isFalse()、isInstanceOf();常用的組合約束logicalOr()、logicalAnd()
。例如檢測(cè)返回的結(jié)果是否是null或ApiApp類。
示例代碼:
?php
namespace Tests\Unit;
use App\Models\ApiApp;
use App\Services\SystemConfigService;
use Tests\TestCase;
class SystemConfigServiceTest extends TestCase
{
/**
* @dataProvider additionProviderGetLatestUpdateAppApi
*
* @param $appType
*/
public function testGetLatestUpdateAppApi($appType)
{
$result = SystemConfigService::getLatestUpdateAppApi($appType);
$this->assertThat($result, $this->logicalOr($this->isNull(), $this->isInstanceOf(ApiApp::class)));
}
public function additionProviderGetLatestUpdateAppApi()
{
return [
'apple' => [1],
'android' => [2],
'null' => [9999]
];
}
}
斷言成功結(jié)果:
3. 對(duì)異常進(jìn)行測(cè)試
使用expectExceptionCode()
對(duì)錯(cuò)誤碼進(jìn)行檢測(cè),不建議對(duì)錯(cuò)誤信息文案進(jìn)行檢測(cè)。例如檢測(cè)設(shè)備被鎖后是否拋出3026錯(cuò)誤碼。
示例代碼:
?php
namespace Tests\Unit;
use App\Services\UserSecurityService;
use Illuminate\Support\Facades\Cache;
use Tests\TestCase;
class UserSecurityServiceTest extends TestCase
{
public static $userId = 4;
/**
* 設(shè)備鎖檢測(cè)
* @throws \App\Exceptions\UserException
*/
public function testDeviceCheckLock()
{
$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);
}
}
斷言成功結(jié)果:
4. 測(cè)試私有屬性和私有方法使用反射機(jī)制
如果只測(cè)試私有方法可使用ReflectionMethod()
反射方法,使用setAccessible(true)
設(shè)置方法可訪問,并使用invokeArgs()或invoke()
調(diào)用方法(invokeArgs將參數(shù)作為數(shù)組傳遞)。例如檢測(cè)IP是否在白名單中。
示例代碼:
被檢測(cè)代碼:
namespace App\Facades\Services;
/**
* Class WebDefender
*/
class WebDefenderService extends BaseService
{
//ip白名單
private $ipWhiteList = [
'10.*',
'172.18.*',
'127.0.0.1'
];
/**
* ip是否在白名單中
*
* @param string $ip
*
* @return bool
*/
private function checkIPWhiteList($ip)
{
if (!$this->ipWhiteList || !is_array($this->ipWhiteList)) {
return false;
}
foreach ($this->ipWhiteList as $item) {
if (preg_match("/{$item}/", $ip)) {
return true;
}
}
return false;
}
}
檢測(cè)方法:
?php
namespace Tests\Unit;
use App\Facades\Services\WebDefenderService;
use Tests\TestCase;
class WebDefenderTest extends TestCase
{
/**
* 測(cè)試IP白名單
* @dataProvider additionProviderIp
*
* @param $ip
* @param $result
*
* @throws \ReflectionException
*/
public function testIPWhite($ip, $result)
{
$checkIPWhiteList = new \ReflectionMethod(WebDefenderService::class, 'checkIPWhiteList');
$checkIPWhiteList->setAccessible(true);
$this->assertEquals($result, $checkIPWhiteList->invokeArgs(new WebDefenderService(), [$ip]));
}
public function additionProviderIp()
{
return [
'10 ip' => ['10.1.1.7', true],
'172 ip' => ['172.18.2.5', true],
'127 ip' => ['127.0.0.1', true],
'192 ip' => ['192.168.0.1', false]
];
}
}
測(cè)試私有屬性可使用ReflectionClass()
, 獲取屬性用getProperty()
, 設(shè)置屬性的值用setValue()
, 獲取方法用getMethod()
, 設(shè)置屬性和方法可被訪問使用setAccessible(true)
。例如檢測(cè)白名單路徑。
示例代碼:
被檢測(cè)代碼:
?php
namespace App\Facades\Services;
use App\Exceptions\ExceptionCode;
use App\Exceptions\UserException;
use Illuminate\Support\Facades\Cache;
/**
* CC攻擊防御器
* Class WebDefender
*/
class WebDefenderService extends BaseService
{
//路徑白名單(正則)
private $pathWhiteList = [
//'^auth\/(.*)',
];
private static $request = null;
/**
* 請(qǐng)求路徑是否在白名單中
*
* @return bool
*/
private function checkPathWhiteList()
{
$path = ltrim(self::$request->getPathInfo(), '/');
if (!$path || !$this->pathWhiteList || !is_array($this->pathWhiteList)) {
return false;
}
foreach ($this->pathWhiteList as $item) {
if (preg_match("/$item/", $path)) {
return true;
}
}
return false;
}
}
檢測(cè)方法:
?php
namespace Tests\Unit;
use App\Facades\Services\WebDefenderService;
use Illuminate\Http\Request;
use Tests\TestCase;
class WebDefenderTest extends TestCase
{
/**
* 檢測(cè)白名單路徑
* @dataProvider additionProviderPathWhiteList
*
* @param $pathProperty
* @param $request
* @param $result
*
* @throws \ReflectionException
*/
public function testCheckPathWhiteList($pathProperty, $request, $result)
{
$reflectedClass = new \ReflectionClass('App\Facades\Services\WebDefenderService');
$webDefenderService = new WebDefenderService();
$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));
}
public function additionProviderPathWhiteList()
{
$allPath = ['.*'];
$checkPath = ['^auth\/(.*)'];
$authSendSmsRequest = new Request([], [], [], [], [], ['HTTP_HOST' => 'api.dev.com', 'REQUEST_URI' => '/auth/sendSms']);
$indexRequest = new Request([], [], [], [], [], ['HTTP_HOST' => 'api.dev.com', 'REQUEST_URI' => '/']);
$noMatchRequest = new Request([], [], [], [], [], ['HTTP_HOST' => 'api.dev.com', 'REQUEST_URI' => '/product/sendSms']);
return [
'index' => [[], $authSendSmsRequest, false],
'no request' => [$allPath, $indexRequest, false],
'all request' => [$allPath, $authSendSmsRequest, true],
'check auth sms' => [$checkPath, $authSendSmsRequest, true],
'check path no match' => [$checkPath, $noMatchRequest, false]
];
}
}
5. 代碼覆蓋率
使用--coverage-html導(dǎo)出的報(bào)告含有類與特質(zhì)覆蓋率、行覆蓋率
、函數(shù)與方法覆蓋率。可查看當(dāng)前單元測(cè)試覆蓋的范圍。例如輸出WebDefenderTest的代碼覆蓋率到桌面(phpunit tests/unit/WebDefenderTest --coverage-html ~/Desktop/test)
6. 指定代碼覆蓋率報(bào)告要包含哪些文件
在配置文件(phpunit.xml)里設(shè)置whitelist中的processUncoveredFilesFromWhitelist=true, 設(shè)置目錄用directory>標(biāo)簽,設(shè)置文件用file>標(biāo)簽。例如指定app/Services目錄下的所有文件和app/Facades/Services/WebDefenderService.php在報(bào)告中。
示例代碼:
?xml version="1.0" encoding="UTF-8"?>
phpunit backupGlobals="false"
backupStaticAttributes="false"
bootstrap="tests/bootstrap.php"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false">
testsuites>
testsuite name="Unit">
directory suffix="Test.php">./tests/Unit/directory>
/testsuite>
testsuite name="Feature">
directory suffix="Test.php">./tests/Feature/directory>
/testsuite>
/testsuites>
filter>
whitelist processUncoveredFilesFromWhitelist="true">
directory suffix=".php">./app/Services/directory>
file>./app/Facades/Services/WebDefenderService.php/file>
/whitelist>
/filter>
php>
server name="APP_ENV" value="local"/>
server name="BCRYPT_ROUNDS" value="4"/>
server name="CACHE_DRIVER" value="credis"/>
server name="MAIL_DRIVER" value="array"/>
server name="QUEUE_CONNECTION" value="sync"/>
server name="SESSION_DRIVER" value="array"/>
server name="APP_CONFIG_CACHE" value="bootstrap/cache/config.phpunit.php"/>
server name="APP_SERVICES_CACHE" value="bootstrap/cache/services.phpunit.php"/>
server name="APP_PACKAGES_CACHE" value="bootstrap/cache/packages.phpunit.php"/>
server name="APP_ROUTES_CACHE" value="bootstrap/cache/routes.phpunit.php"/>
server name="APP_EVENTS_CACHE" value="bootstrap/cache/events.phpunit.php"/>
/php>
/phpunit>
7. 參考文檔
PHPUnit官方文檔 https://phpunit.readthedocs.io/zh_CN/latest/index.html
反射類 https://www.php.net/manual/en/class.reflectionclass.php
反射方法 https://www.php.net/manual/en/class.reflectionmethod.php
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
您可能感興趣的文章:- 詳解Yaf框架PHPUnit集成測(cè)試方法
- PHP單元測(cè)試配置與使用方法詳解
- PHP使用phpunit進(jìn)行單元測(cè)試示例
- php使用yield對(duì)性能提升的測(cè)試實(shí)例分析
- 高質(zhì)量PHP代碼的50個(gè)實(shí)用技巧必備(下)
- 高質(zhì)量PHP代碼的50個(gè)實(shí)用技巧必備(上)
- 很讓人受教的 提高php代碼質(zhì)量36計(jì)
- 寫出高質(zhì)量的PHP程序
- 淺談如何提高PHP代碼質(zhì)量之端到端集成測(cè)試