亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 語言 > PHP > 正文

使用PHPUnit進行單元測試并生成代碼覆蓋率報告的方法

2024-05-05 00:07:15
字體:
來源:轉載
供稿:網友

安裝PHPUnit

使用 Composer 安裝 PHPUnit

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

使用Composer構建你的項目

我們將新建一個unit項目用于演示單元測試的基本工作流

創建項目結構

mkdir unit && cd unit && mkdir app tests reports#結構如下./├── app #存放業務代碼├── reports #存放覆蓋率報告└── tests #存放單元測試

使用Composer構建工程

#一路回車即可composer init#注冊命名空間vi composer.json...  "autoload": {    "psr-4": {      "App//": "app/",      "Tests//": "tests/"    }  }...#更新命名空間composer dump-autoload#安裝 phpunit 組件庫composer require --dev phpunit/phpunit

到此我們就完成項目框架的構建,下面開始寫業務和測試用例。

編寫測試用例

創建文件app/Example.php 這里我為節省排版就不寫注釋了

<?phpnamespace 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;  }}

創建相應的測試文件tests/ExampleTest.php

<?phpnamespace 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");  }}

執行單元測試

[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.00MBThere was 1 failure:1) Tests/ExampleTest::testGetMsgFailed 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:148FAILURES!Tests: 3, Assertions: 3, Failures: 1.

這是一個非常簡單的測試用例類,可以看到,執行了共3個測試用例,共3個斷言,共1個失敗,可以參照PHPUnit手冊學習更多高級用法。

代碼覆蓋率

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

測試覆蓋率的檢測對象是我們的業務代碼,PHPUnit通過檢測我們編寫的測試用例調用了哪些函數,哪些類,哪些方法,每一個控制流程是否都執行了一遍來計算覆蓋率。

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.

同時需要使用 --whitelist dir參數來設定我們需要檢測覆蓋率的業務代碼路徑,下面演示一下具體操作:

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

PHPUnit,單元測試,代碼

PHPUnit,單元測試,代碼

這樣我們就對業務代碼App/Example做單元測試,并且獲得我們單元測試的代碼覆蓋率,現在自然是百分之百,因為我的測試用例已經訪問了App/Example的所有方法,沒有遺漏的,開發中則能體現出你的測試時用力對業務代碼測試度的完善性。

基境共享測試數據

可能你會發現我們在每個測試方法中都創建了App/Example對象,在一些場景下是重復勞動,為什么不能只創建一次然后供其他測試方法訪問呢?這需要理解 PHPUnit 執行測試用例的工作流程。

我們沒有辦法在不同的測試方法中通過某成員屬性來傳遞數據,因為每個測試方法的執行都是新建一個測試類對象,然后調用相應的測試方法。

即測試的執行模式并不是

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

而是

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

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

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

public static function setUpBeforeClass()/tearDownAfterClass()//測試類構建/解構時調用protected function setUp()/tearDown()//測試方法執行前/后調用protected function assertPreConditions()/assertPostConditions()//斷言前/后調用

當運行測試時,每個測試類大致就是如下的執行步驟

#測試類基境構建setUpBeforeClass#new一個測試類對象#第一個測試用例setUpassertPreConditionsassertPostConditionstearDown#new一個測試類對象#第二個測試用例setUpassertPreConditionsassertPostConditionstearDown...#測試類基境解構tearDownAfterClass

所以我們可以在測試類構建時使用setUpBeforeClass創建一個 App/Example 對象作為測試類的靜態成員變量(tearDownAfterClass主要用于一些資源清理,比如關閉文件,數據庫連接),然后讓每一個測試方法用例使用它:

<?phpnamespace Tests;use App/Example;use PHPUnit/Framework/TestCase as BaseTestCase;class ExampleTest extends BaseTestCase{  // 類靜態屬性  private static $example;  public static function setUpBeforeClass()  {    self::$example = new Example();  }  public function testGetTrue()  {    // 類的靜態屬性更新    self::$example->setMsg("hello big_cat");    $result = self::$example->getTrue();    $this->assertTrue($result);  }  public function testGetFalse()  {    $result = self::$example->getFalse();    $this->assertFalse($result);  }  /**   * 依賴 testGetTrue 執行完畢   * @depends testGetTrue   * @return [type] [description]   */  public function testGetMsg()  {    $result = self::$example->getMsg();    $this->assertEquals($result, "hello big_cat");  }}

或者使用@depends注解來聲明二者的執行順序,并使用傳遞參數的方式來滿足需求。

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

理解測試執行的模式還是很有幫助的,其他高級特性請瀏覽官方文檔。

使用phpunit.xml編排測試套件

使用測試套件來管理測試,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>    <!--可以定義多個 suffix 用于指定待執行的測試類文件后綴-->    <testsuite name="Tests">      <directory suffix="Test.php">./test</directory>    </testsuite>  </testsuites>  <filter>    <whitelist processUncoveredFilesFromWhitelist="true">      <!--可以定義多個 對./app下的業務代碼做覆蓋率統計-->      <directory suffix=".php">./app</directory>    </whitelist>  </filter>  <logging>    <!--覆蓋率報告生成類型和輸出目錄 lowUpperBound低覆蓋率閾值 highLowerBound高覆蓋率閾值-->    <log type="coverage-html" target="./reports" lowUpperBound="35" highLowerBound="70"/>  </logging></phpunit>

然后直接運phpunit行即可:

[root@localhost unit]# phpunit PHPUnit 6.5.14 by Sebastian Bergmann and contributors.Time: 81 ms, Memory: 4.00MBNo tests executed!Generating code coverage report in HTML format ... done

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持VeVb武林網。


注:相關教程知識閱讀請移步到PHP教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表

圖片精選

亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
欧美亚洲视频在线观看| 国产一区红桃视频| 亚洲欧美在线磁力| 亚洲精品视频网上网址在线观看| 国产精品久久久久久久久| 麻豆精品精华液| 国产成人综合精品在线| 午夜剧场成人观在线视频免费观看| 欧美激情国内偷拍| 日韩精品www| 亚洲人免费视频| 中文字幕在线看视频国产欧美| 国产精品亚洲激情| 久久手机免费视频| 欧美性xxxx18| 国产亚洲精品美女久久久| 亚洲成人a级网| 亚洲欧美综合v| 国产精品久久久久久久久久东京| 欧美激情一区二区三区在线视频观看| 97精品一区二区三区| 国产中文日韩欧美| 黑人欧美xxxx| 成人春色激情网| 国产日韩在线看片| 亚洲欧洲日产国码av系列天堂| 国产精自产拍久久久久久蜜| 欧美亚洲视频在线观看| 日韩精品一区二区三区第95| 国产一区二区黑人欧美xxxx| 日韩在线小视频| 日韩欧美亚洲国产一区| 日韩a**中文字幕| 成人免费视频xnxx.com| 欧美午夜宅男影院在线观看| 国产精品欧美一区二区| 欧美综合一区第一页| 国内免费精品永久在线视频| 欧美日韩国产激情| 亚洲最大的免费| 狠狠躁夜夜躁人人躁婷婷91| 欧美一级电影免费在线观看| 亚洲区免费影片| 91免费高清视频| 国产精欧美一区二区三区| 欧美成人精品激情在线观看| 国产精品极品美女在线观看免费| 欧美亚洲一级片| 国产亚洲美女精品久久久| 欧美日韩一二三四五区| 91国产视频在线| 国产精品久久久久久久av电影| 亚洲人成电影在线观看天堂色| 亚洲欧美日韩精品久久亚洲区| 欧美激情在线有限公司| 成人97在线观看视频| 亚洲a∨日韩av高清在线观看| 一区二区三区www| 亚洲欧美国内爽妇网| 国产精品久久久久久久久久小说| 欧美电影免费播放| 久久天天躁夜夜躁狠狠躁2022| 亚洲成人网在线观看| 中文字幕亚洲欧美一区二区三区| 欧美视频在线看| 国产成人一区二区三区电影| 亚洲黄色av女优在线观看| 国产精品老女人视频| 中文字幕国产亚洲2019| 午夜欧美不卡精品aaaaa| 国产一区二区丝袜高跟鞋图片| 亚洲男人av电影| 77777亚洲午夜久久多人| 美女av一区二区三区| 91免费版网站入口| 日韩精品极品视频免费观看| 国产成人一区三区| 神马久久久久久| 欧美壮男野外gaytube| 亚洲人成啪啪网站| 国产成人精品久久亚洲高清不卡| 久久人体大胆视频| 国产成人综合精品在线| 久久久国产精品免费| 日韩性xxxx爱| 欧美激情aaaa| 亚洲国产毛片完整版| 欧美—级a级欧美特级ar全黄| 日韩av在线天堂网| 亚洲天堂av网| 不卡av电影在线观看| 欧美特级www| 精品国产视频在线| 永久免费毛片在线播放不卡| 在线视频欧美性高潮| 最新69国产成人精品视频免费| 色综合老司机第九色激情| 日韩欧美在线看| 欧美性猛交xxxx黑人猛交| 欧美亚洲国产成人精品| 亚洲视频在线观看视频| 久久久久女教师免费一区| 国产在线视频2019最新视频| 日韩专区在线观看| 国产午夜精品一区二区三区| 96精品久久久久中文字幕| 日韩暖暖在线视频| 午夜精品久久久久久久男人的天堂| 精品福利在线看| 亚洲精品久久久久中文字幕欢迎你| 精品国产一区二区三区久久久狼| 色偷偷av亚洲男人的天堂| 欧美激情一区二区三区高清视频| 欧美孕妇毛茸茸xxxx| 久久亚洲私人国产精品va| 亚洲国产精品久久久久秋霞蜜臀| 国产在线视频2019最新视频| 免费不卡欧美自拍视频| 91精品综合久久久久久五月天| 青青在线视频一区二区三区| 国产区精品视频| 精品亚洲精品福利线在观看| 成人啪啪免费看| 国内精品一区二区三区| 中文字幕欧美亚洲| 性欧美暴力猛交69hd| 成人黄色av播放免费| 亚洲日韩欧美视频一区| 久久天天躁狠狠躁夜夜av| 色多多国产成人永久免费网站| 成人精品久久av网站| 欧美成aaa人片免费看| 国产98色在线| 美日韩丰满少妇在线观看| 亚洲香蕉在线观看| 久久人人97超碰精品888| 亚洲精品aⅴ中文字幕乱码| 精品亚洲国产成av人片传媒| 国内偷自视频区视频综合| 国产ts人妖一区二区三区| 欧美日韩成人在线观看| 欧美高清理论片| 高清一区二区三区四区五区| 久久久国产精彩视频美女艺术照福利| 国产热re99久久6国产精品| 欧美极品美女视频网站在线观看免费| 欧美日韩免费在线| 欧美日韩在线视频一区| 欧美国产日韩视频| 久久久综合免费视频| 久久久精品影院| 中文字幕精品视频| 久久久久久午夜| 国产成人精品最新| 国产精品久久久久91| 欧美日韩在线一区| 欧美日韩在线免费观看| 热久久免费视频精品| 一区二区成人av| 精品久久久久久电影| 一级做a爰片久久毛片美女图片| 日日骚久久av| 97国产一区二区精品久久呦| 97久久超碰福利国产精品…|