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 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]] ]; } }
断言成功结果:
2. 断言方法
常用有asserttrue(), assertfalse(), assertnull(), assertequals(), assertthat()。
assertthat()自定义断言。常用的约束有isnull()、istrue()、isfalse()、isinstanceof();常用的组合约束logicalor()、logicaland()
。例如检测返回的结果是否是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] ]; } }
断言成功结果:
3. 对异常进行测试
使用expectexceptioncode()
对错误码进行检测,不建议对错误信息文案进行检测。例如检测设备被锁后是否抛出3026错误码。
示例代码:
<?php namespace tests\unit; use app\services\usersecurityservice; use illuminate\support\facades\cache; use tests\testcase; class usersecurityservicetest extends testcase { public static $userid = 4; /** * 设备锁检测 * @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); } }
断言成功结果:
4. 测试私有属性和私有方法使用反射机制
如果只测试私有方法可使用reflectionmethod()
反射方法,使用setaccessible(true)
设置方法可访问,并使用invokeargs()或invoke()
调用方法(invokeargs将参数作为数组传递)。例如检测ip是否在白名单中。
示例代码:
被检测代码:
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; } }
检测方法:
<?php namespace tests\unit; use app\facades\services\webdefenderservice; use tests\testcase; class webdefendertest extends testcase { /** * 测试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] ]; } }
测试私有属性可使用reflectionclass()
, 获取属性用getproperty()
, 设置属性的值用setvalue()
, 获取方法用getmethod()
, 设置属性和方法可被访问使用setaccessible(true)
。例如检测白名单路径。
示例代码:
被检测代码:
<?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; /** * 请求路径是否在白名单中 * * @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; } }
检测方法:
<?php namespace tests\unit; use app\facades\services\webdefenderservice; use illuminate\http\request; use tests\testcase; class webdefendertest extends testcase { /** * 检测白名单路径 * @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导出的报告含有类与特质覆盖率、行覆盖率
、函数与方法覆盖率。可查看当前单元测试覆盖的范围。例如输出webdefendertest的代码覆盖率到桌面(phpunit tests/unit/webdefendertest --coverage-html ~/desktop/test)
6. 指定代码覆盖率报告要包含哪些文件
在配置文件(phpunit.xml)里设置whitelist中的processuncoveredfilesfromwhitelist=true, 设置目录用<directory>标签,设置文件用<file>标签。例如指定app/services目录下的所有文件和app/facades/services/webdefenderservice.php在报告中。
示例代码:
<?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
反射类
反射方法
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
上一篇: PS设计皮革质感文件夹图标