激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術(shù)|正則表達(dá)式|C/C++|IOS|C#|Swift|Android|VB|R語(yǔ)言|JavaScript|易語(yǔ)言|vb.net|

服務(wù)器之家 - 編程語(yǔ)言 - PHP教程 - 使用PHPUnit進(jìn)行單元測(cè)試并生成代碼覆蓋率報(bào)告的方法

使用PHPUnit進(jìn)行單元測(cè)試并生成代碼覆蓋率報(bào)告的方法

2019-06-04 15:08big_cat服務(wù)器之家 PHP教程

這篇文章主要介紹了使用PHPUnit進(jìn)行單元測(cè)試并生成代碼覆蓋率報(bào)告的方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧

安裝PHPUnit

使用 Composer 安裝 PHPUnit

#查看composer的全局bin目錄 將其加入系統(tǒng) path 路徑 方便后續(xù)直接運(yùn)行安裝的命令
composer global config bin-dir --absolute
#全局安裝 phpunit
composer global require --dev phpunit/phpunit
#查看版本
phpunit --version

使用Composer構(gòu)建你的項(xiàng)目

我們將新建一個(gè)unit項(xiàng)目用于演示單元測(cè)試的基本工作流

創(chuàng)建項(xiàng)目結(jié)構(gòu)

mkdir unit && cd unit && mkdir app tests reports
#結(jié)構(gòu)如下
./
├── app #存放業(yè)務(wù)代碼
├── reports #存放覆蓋率報(bào)告
└── tests #存放單元測(cè)試

使用Composer構(gòu)建工程

#一路回車即可
composer init

#注冊(cè)命名空間
vi composer.json
...
  "autoload": {
    "psr-4": {
      "App\\": "app/",
      "Tests\\": "tests/"
    }
  }
...
#更新命名空間
composer dump-autoload

#安裝 phpunit 組件庫(kù)
composer require --dev phpunit/phpunit

到此我們就完成項(xiàng)目框架的構(gòu)建,下面開始寫業(yè)務(wù)和測(cè)試用例。

編寫測(cè)試用例

創(chuàng)建文件app/Example.php 這里我為節(jié)省排版就不寫注釋了

<?php
namespace App;

class Example
{
  private $msg = "hello world";

  public function getTrue()
  {
    return true;
  }

  public function getFalse()
  {
    return false;
  }

  public function setMsg($value)
  {
    $this->msg = $value;
  }

  public function getMsg()
  {
    return $this->msg;
  }
}

創(chuàng)建相應(yīng)的測(cè)試文件tests/ExampleTest.php

<?php
namespace Tests;

use PHPUnit\Framework\TestCase as BaseTestCase;
use App\Example;

class ExampleTest extends BaseTestCase
{
  public function testGetTrue()
  {
    $example = new Example();
    $result = $example->getTrue();
    $this->assertTrue($result);
  }
  
  public function testGetFalse()
  {
    $example = new Example();
    $result = $example->getFalse();
    $this->assertFalse($result);
  }
  
  public function testGetMsg()
  {
    $example = new Example();
    $result = $example->getTrue();
    // $result is world not big_cat
    $this->assertEquals($result, "hello big_cat");
  }
}

執(zhí)行單元測(cè)試

[root@localhost unit]# phpunit --bootstrap=vendor/autoload.php \
tests/

PHPUnit 6.5.14 by Sebastian Bergmann and contributors.

..F                                 3 / 3 (100%)

Time: 61 ms, Memory: 4.00MB

There was 1 failure:

1) Tests\ExampleTest::testGetMsg
Failed asserting that 'hello big_cat' matches expected true.

/opt/unit/tests/ExampleTest.php:27
/root/.config/composer/vendor/phpunit/phpunit/src/TextUI/Command.php:195
/root/.config/composer/vendor/phpunit/phpunit/src/TextUI/Command.php:148

FAILURES!
Tests: 3, Assertions: 3, Failures: 1.

這是一個(gè)非常簡(jiǎn)單的測(cè)試用例類,可以看到,執(zhí)行了共3個(gè)測(cè)試用例,共3個(gè)斷言,共1個(gè)失敗,可以參照PHPUnit手冊(cè)學(xué)習(xí)更多高級(jí)用法。

代碼覆蓋率

代碼覆蓋率反應(yīng)的是測(cè)試用例對(duì)測(cè)試對(duì)象行,函數(shù)/方法,類/特質(zhì)的訪問(wèn)率是多少(PHP_CodeCoverage 尚不支持 Opcode覆蓋率、分支覆蓋率 及 路徑覆蓋率),雖然有很多人認(rèn)為過(guò)分看重覆蓋率是不對(duì)的,但我們初入測(cè)試還是俗氣的追求一下吧。

測(cè)試覆蓋率的檢測(cè)對(duì)象是我們的業(yè)務(wù)代碼,PHPUnit通過(guò)檢測(cè)我們編寫的測(cè)試用例調(diào)用了哪些函數(shù),哪些類,哪些方法,每一個(gè)控制流程是否都執(zhí)行了一遍來(lái)計(jì)算覆蓋率。

PHPUnit 的覆蓋率依賴 Xdebug,可以生成多種格式:

--coverage-clover <file>  Generate code coverage report in Clover XML format.
--coverage-crap4j <file>  Generate code coverage report in Crap4J XML format.
--coverage-html <dir>    Generate code coverage report in HTML format.
--coverage-php <file>    Export PHP_CodeCoverage object to file.
--coverage-text=<file>   Generate code coverage report in text format.
--coverage-xml <dir>    Generate code coverage report in PHPUnit XML format.

同時(shí)需要使用 --whitelist dir參數(shù)來(lái)設(shè)定我們需要檢測(cè)覆蓋率的業(yè)務(wù)代碼路徑,下面演示一下具體操作:

phpunit \
--bootstrap vendor/autoload.php \
--coverage-html=reports/ \
--whitelist app/ \
tests/
#查看覆蓋率報(bào)告
cd reports/ && php -S 0.0.0.0:8899

使用PHPUnit進(jìn)行單元測(cè)試并生成代碼覆蓋率報(bào)告的方法

使用PHPUnit進(jìn)行單元測(cè)試并生成代碼覆蓋率報(bào)告的方法

這樣我們就對(duì)業(yè)務(wù)代碼App\Example做單元測(cè)試,并且獲得我們單元測(cè)試的代碼覆蓋率,現(xiàn)在自然是百分之百,因?yàn)槲业臏y(cè)試用例已經(jīng)訪問(wèn)了App\Example的所有方法,沒(méi)有遺漏的,開發(fā)中則能體現(xiàn)出你的測(cè)試時(shí)用力對(duì)業(yè)務(wù)代碼測(cè)試度的完善性。

基境共享測(cè)試數(shù)據(jù)

可能你會(huì)發(fā)現(xiàn)我們?cè)诿總€(gè)測(cè)試方法中都創(chuàng)建了App\Example對(duì)象,在一些場(chǎng)景下是重復(fù)勞動(dòng),為什么不能只創(chuàng)建一次然后供其他測(cè)試方法訪問(wèn)呢?這需要理解 PHPUnit 執(zhí)行測(cè)試用例的工作流程。

我們沒(méi)有辦法在不同的測(cè)試方法中通過(guò)某成員屬性來(lái)傳遞數(shù)據(jù),因?yàn)槊總€(gè)測(cè)試方法的執(zhí)行都是新建一個(gè)測(cè)試類對(duì)象,然后調(diào)用相應(yīng)的測(cè)試方法

即測(cè)試的執(zhí)行模式并不是

testObj = new ExampleTest();
testObj->testMethod1();
testObj->testMethod2();

而是

testObj1 = new ExampleTest();
testObj1->testMethod1();

testObj2 = new ExampleTest();
testObj2->testMethod2();

所以testMethod1()修改的屬性狀態(tài)無(wú)法傳遞給 testMethod2()使用。

PHPUnit則為我們提供了全面的hook接口:

public static function setUpBeforeClass()/tearDownAfterClass()//測(cè)試類構(gòu)建/解構(gòu)時(shí)調(diào)用
protected function setUp()/tearDown()//測(cè)試方法執(zhí)行前/后調(diào)用
protected function assertPreConditions()/assertPostConditions()//斷言前/后調(diào)用

當(dāng)運(yùn)行測(cè)試時(shí),每個(gè)測(cè)試類大致就是如下的執(zhí)行步驟

#測(cè)試類基境構(gòu)建
setUpBeforeClass

#new一個(gè)測(cè)試類對(duì)象
#第一個(gè)測(cè)試用例
setUp
assertPreConditions
assertPostConditions
tearDown

#new一個(gè)測(cè)試類對(duì)象
#第二個(gè)測(cè)試用例
setUp
assertPreConditions
assertPostConditions
tearDown
...

#測(cè)試類基境解構(gòu)
tearDownAfterClass

所以我們可以在測(cè)試類構(gòu)建時(shí)使用setUpBeforeClass創(chuàng)建一個(gè) App\Example 對(duì)象作為測(cè)試類的靜態(tài)成員變量(tearDownAfterClass主要用于一些資源清理,比如關(guān)閉文件,數(shù)據(jù)庫(kù)連接),然后讓每一個(gè)測(cè)試方法用例使用它:

<?php
namespace Tests;

use App\Example;
use PHPUnit\Framework\TestCase as BaseTestCase;

class ExampleTest extends BaseTestCase
{
  // 類靜態(tài)屬性
  private static $example;

  public static function setUpBeforeClass()
  {
    self::$example = new Example();
  }

  public function testGetTrue()
  {
    // 類的靜態(tài)屬性更新
    self::$example->setMsg("hello big_cat");
    $result = self::$example->getTrue();
    $this->assertTrue($result);
  }

  public function testGetFalse()
  {
    $result = self::$example->getFalse();
    $this->assertFalse($result);
  }

  /**
   * 依賴 testGetTrue 執(zhí)行完畢
   * @depends testGetTrue
   * @return [type] [description]
   */
  public function testGetMsg()
  {
    $result = self::$example->getMsg();
    $this->assertEquals($result, "hello big_cat");
  }
}

或者使用@depends注解來(lái)聲明二者的執(zhí)行順序,并使用傳遞參數(shù)的方式來(lái)滿足需求。

public function testMethod1()
{
  $this->assertTrue(true);
  return "hello";
}

/**
 * @depends testMethod1
 */
public function testMethod2($str)
{
  $this->assertEquals("hello", $str);
}
#執(zhí)行模式大概如下
testObj1 = new Test;
$str = testObj1->testMethod1();

testObj2 = new Test;
testObj2->testMethod2($str);

理解測(cè)試執(zhí)行的模式還是很有幫助的,其他高級(jí)特性請(qǐng)瀏覽官方文檔。

使用phpunit.xml編排測(cè)試套件

使用測(cè)試套件來(lái)管理測(cè)試,vi phpunit.xml

<?xml version="1.0" encoding="UTF-8"?>
<phpunit backupGlobals="false"
     backupStaticAttributes="false"
     bootstrap="./vendor/autoload.php"
     colors="true"
     convertErrorsToExceptions="true"
     convertNoticesToExceptions="true"
     convertWarningsToExceptions="true"
     processIsolation="false"
     stopOnFailure="false">
  <testsuites>
    <!--可以定義多個(gè) suffix 用于指定待執(zhí)行的測(cè)試類文件后綴-->
    <testsuite name="Tests">
      <directory suffix="Test.php">./test</directory>
    </testsuite>
  </testsuites>
  <filter>
    <whitelist processUncoveredFilesFromWhitelist="true">
      <!--可以定義多個(gè) 對(duì)./app下的業(yè)務(wù)代碼做覆蓋率統(tǒng)計(jì)-->
      <directory suffix=".php">./app</directory>
    </whitelist>
  </filter>
  <logging>
    <!--覆蓋率報(bào)告生成類型和輸出目錄 lowUpperBound低覆蓋率閾值 highLowerBound高覆蓋率閾值-->
    <log type="coverage-html" target="./reports" lowUpperBound="35" highLowerBound="70"/>
  </logging>
</phpunit>

然后直接運(yùn)phpunit行即可:

[root@localhost unit]# phpunit 
PHPUnit 6.5.14 by Sebastian Bergmann and contributors.

Time: 81 ms, Memory: 4.00MB

No tests executed!

Generating code coverage report in HTML format ... done

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持服務(wù)器之家。

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 做爰裸体激情2 | 亚洲精品免费播放 | 亚洲第一页中文字幕 | 一级毛片高清 | 激情视频免费看 | 欧美日韩网站在线观看 | 天天干导航 | 国产乱淫a∨片免费观看 | 国产精品99久久久久久宅女 | 亚洲精品久久久久久下一站 | 日韩精品一二三 | 美国一级免费视频 | 在线2区| 欧美一二在线 | 午夜a级片 | 九九看片 | 日韩字幕 | 日本在线精品视频 | 免费放黄网站在线播放 | av成人免费在线观看 | 亚洲福利在线免费观看 | 欧美精品一区二区三区久久久 | 国产无区一区二区三麻豆 | 免费黄色小网站 | 精品国产99久久久久久宅男i | 全黄性性激高免费视频 | 美女av在线免费观看 | 午夜精品久久久久久中宇 | 在线成人免费观看视频 | 97超级碰碰人国产在线观看 | 国产高潮好爽受不了了夜色 | 亚洲精品一区二区三区大胸 | 国产精品av久久久久久久久久 | 今井夏帆av一区二区 | 欧美另类在线视频 | 国产大片中文字幕在线观看 | 中国大陆一级毛片 | 久久久一区二区三区精品 | 成人一级黄色片 | 成人午夜亚洲 | 久久靖品 |