溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

PHPUnit中使用 Laravel怎么實現(xiàn)單元測試

發(fā)布時間:2021-06-12 18:29:30 來源:億速云 閱讀:158 作者:Leah 欄目:開發(fā)技術(shù)

本篇文章為大家展示了PHPUnit中使用 Laravel怎么實現(xiàn)單元測試,內(nèi)容簡明扼要并且容易理解,絕對能使你眼前一亮,通過這篇文章的詳細介紹希望你能有所收獲。

1. 數(shù)據(jù)供給器

用來提供參數(shù)和結(jié)果,使用 @dataProvider 標注來指定使用哪個數(shù)據(jù)供給器方法。例如檢測app升級數(shù)據(jù)是否符合預(yù)期,addProviderAppUpdateData()提供測試的參數(shù)和結(jié)果。testAppUpdateData()檢測appUpdateData()返回的結(jié)果是否和給定的預(yù)期結(jié)果相等,即如果$appId='apple_3.3.2_117', $result=['status' => 0, 'isIOS' => false], 則$data中如果含有['status' => 0, 'isIOS' => false], 則斷言成功。建議在數(shù)據(jù)提供器,逐個用字符串鍵名對其命名,這樣在斷言失敗的時候?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]],
        'h6'          => ['h6_3.3.3', ['status' => 1, 'isIOS' => false]]
      ];
    }
  }

斷言成功結(jié)果:

PHPUnit中使用 Laravel怎么實現(xiàn)單元測試

2. 斷言方法

常用有assertTrue(), assertFalse(), assertNull(), assertEquals(), assertThat()。

assertThat()自定義斷言。常用的約束有isNull()、isTrue()、isFalse()、isInstanceOf();常用的組合約束logicalOr()、logicalAnd()。例如檢測返回的結(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é)果:

PHPUnit中使用 Laravel怎么實現(xiàn)單元測試

3. 對異常進行測試

使用expectExceptionCode()對錯誤碼進行檢測,不建議對錯誤信息文案進行檢測。例如檢測設(shè)備被鎖后是否拋出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;

    /**
     * 設(shè)備鎖檢測
     * @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é)果:

PHPUnit中使用 Laravel怎么實現(xiàn)單元測試

4. 測試私有屬性和私有方法使用反射機制

如果只測試私有方法可使用ReflectionMethod()反射方法,使用setAccessible(true)設(shè)置方法可訪問,并使用invokeArgs()或invoke()調(diào)用方法(invokeArgs將參數(shù)作為數(shù)組傳遞)。例如檢測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(), 設(shè)置屬性的值用setValue(), 獲取方法用getMethod(), 設(shè)置屬性和方法可被訪問使用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導(dǎo)出的報告含有類與特質(zhì)覆蓋率、行覆蓋率、函數(shù)與方法覆蓋率。可查看當前單元測試覆蓋的范圍。例如輸出WebDefenderTest的代碼覆蓋率到桌面(phpunit tests/unit/WebDefenderTest --coverage-html ~/Desktop/test)

PHPUnit中使用 Laravel怎么實現(xiàn)單元測試

6. 指定代碼覆蓋率報告要包含哪些文件

在配置文件(phpunit.xml)里設(shè)置whitelist中的processUncoveredFilesFromWhitelist=true, 設(shè)置目錄用<directory>標簽,設(shè)置文件用<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>

上述內(nèi)容就是PHPUnit中使用 Laravel怎么實現(xiàn)單元測試,你們學到知識或技能了嗎?如果還想學到更多技能或者豐富自己的知識儲備,歡迎關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI