使用PHPunit

背景

PHPUnit 是一個面向PHP開發(fā)者的測試框架,可以寫提供編程代碼質(zhì)量,確保項(xiàng)目可以持續(xù)維護(hù)

安裝phpunit

項(xiàng)目不采用全局安裝 ,我們使用composer安裝phpunit

composer require --dev phpunit/phpunit 5.7.27

備注:支持PHP5.6版本

創(chuàng)建配置文件

phpunit.xml放置在項(xiàng)目的根目錄中,是phpunit默認(rèn)讀取的配置文件,實(shí)現(xiàn)配置執(zhí)行單元測試執(zhí)行的初始化文件,測試套件目錄
默認(rèn)情況下,你應(yīng)用程序的 tests 目錄下包含兩個子目錄:Feature 和 Unit。

單元測試(Unit)是針對你的代碼中非常少,而且相對獨(dú)立的一部分代碼來進(jìn)行的測試。實(shí)際上,大部分單元測試都是針對單個方法進(jìn)行的。

功能測試(Feature)能測試你的大部分代碼,包括多個對象如何相互交互,甚至是對 JSON 端點(diǎn)的完整 HTTP 請求。 通常,你的大多數(shù)測試應(yīng)該是功能測試。這些類型的測試可以最大程度地確保你的系統(tǒng)作為一個整體按預(yù)期運(yùn)行。

配置自動加載

我們在composer.json添加autoload規(guī)則,使用psr-4的自動加載類

"require-dev": {
    "phpunit/phpunit": "5.7.27"
 },
"autoload-dev": {
    "psr-4": {
        "Tests\\": "tests/"
    }
}

執(zhí)行類自動加載
composer dump-autoload --optimize

執(zhí)行單元測試

./vendor/bin/phpunit -c ./phpunit.xml

只允許以下指定用例

./vendor/bin/phpunit --filter OrderVehicleNewTest --debug

官方手冊

應(yīng)用到項(xiàng)目中實(shí)踐

配置phpunit.xml

<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="./vendor/phpunit/phpunit/phpunit.xsd"
         bootstrap="./protect/__init__.php"
         colors="true"
         stopOnFailure="true"
         verbose="true"
>
    <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">./protect</directory>
        </whitelist>
    </filter>
    <php> <!--https://www.kancloud.cn/manual/phpunit-book/68752-->
        <server name="APP_ENV" value="testing"/>
    </php>
</phpunit>

執(zhí)行腳本

<?php
require_once dirname(__FILE__) . '/../__init__.php';
class Script_Phpunit extends \PHPUnit_TextUI_Command{
    public static function main($exit = true){
        $command = new static;
        array_pop($_SERVER['argv']);
        return $command->run($_SERVER['argv'], $exit);
    }
}
//控制環(huán)境執(zhí)行
if(in_array(HLL_ENV,['dev','stg','pre_1'])){
    (new Script_Phpunit)->main();
}

應(yīng)用基礎(chǔ)類

<?php
namespace Tests;
use PHPUnit\Framework\TestCase;

abstract class TestBaseCase extends TestCase
{

    protected $commit = false; //是否提交事務(wù)



    /**
     * @notes: 測試用例類的第一個測試之前
     * @author: jackin.chen
     * @time: 2022/10/20 16:57
     * @function: setUpBeforeClass
     */
    public static function setUpBeforeClass()
    {

    }



    /**
     * @notes: 在運(yùn)行每個測試方法前自動調(diào)用
     * @author: jackin.chen
     * @time: 2022/10/10 10:33
     * @function: setUp
     */
    protected function setUp()
    {
        //見:https://github.com/sebastianbergmann/phpunit/issues/1598
        if (!empty(\PHPUnit_Util_Blacklist::$blacklistedClassNames)) {
            foreach (\PHPUnit_Util_Blacklist::$blacklistedClassNames as $className => $parent) {
                try {
                    if (!class_exists($className)) {
                        unset(\PHPUnit_Util_Blacklist::$blacklistedClassNames[$className]);
                    }
                } catch (\Exception $e) {
                    unset(\PHPUnit_Util_Blacklist::$blacklistedClassNames[$className]);
                }
            }
        }
        //在配置xml直接配置啟動文件
        //require_once (__DIR__ .'/../protect/__init__.php');
    }

    /**
     * @notes: 會在每個測試方法允許后被調(diào)用
     * @author: jackin.chen
     * @time: 2022/10/16 14:49
     * @function: tearDown
     */
    public function tearDown()
    {

    }


    /**
     * @notes: 對比JSON驗(yàn)證數(shù)據(jù)
     * @param $response
     * @param $expected
     * @param string $msg
     * @return $this
     * @author: jackin.chen
     * @time: 2022/10/20 13:49
     * @function: assertJsonString
     */
    protected function assertJsonString($response,$expected,$msg = 'msg'){

        $this->assertNotEmpty($response);
        $this->assertNotEmpty($expected);
        $this->assertArrayHasKey($msg,$response);
        $expect = $decoded = [];
        foreach ($expected as $key => $value){
            if(isset($response[$key])){
                $expect[$key] = $value; // 期望值
                $decoded[$key] = $response[$key]; //返回值
            }
        }
        $message =  isset($response[$msg]) ? $response[$msg] : '';
        $expectedJson = json_encode($expect, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
        $actualJson = json_encode($decoded, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
        $this->assertJsonStringEqualsJsonString($expectedJson,$actualJson,$message);
        return $this;
    }


    /**
     * @notes:
     * @param string $uri 路由地址
     * @param mixed $parameters 參數(shù)
     * @return false|mixed
     * @author: jackin.chen
     * @time: 2022/10/10 10:21
     * @function: call
     */
    protected function call($uri,$parameters){
        $uri = self::prepareUrlForRequest($uri);
        list($class,$action) = explode('/',$uri);
        $_GET['_m'] = $class;
        $_GET['_a'] = $action;
        $controller = 'Ctrller_'.ucfirst($class);
        ob_start();
        $instance = new $controller;
        $result = call_user_func_array([$instance, $action], [$parameters]);
        if(!is_array($result)){
            $json = ob_get_contents();
            $result =  \Lib_Func::jsonDecode($json);
        }
        ob_end_clean();
        return  $result;
    }


    /**
     * @notes: 下劃線轉(zhuǎn)大駝峰
     * @param string $words
     * @param string $separator
     * @return string
     * @author: jackin.chen
     * @time: 2022/10/10 10:16
     * @function: prepareUrlForRequest
     */
    protected function prepareUrlForRequest($words,$separator='_')
    {
        $words = $separator. str_replace($separator, " ", strtolower($words));
        return ltrim(str_replace(" ", "", ucwords($words)), $separator );
    }

    /**
     * @notes: 使用事務(wù)調(diào)試接口避免臟數(shù)據(jù)
     * @param \Closure $callback
     * @param array $parameters
     * @return false|mixed
     * @author: jackin.chen
     * @time: 2022/10/10 11:18
     * @function: transaction
     */
    protected function transaction(\Closure $callback,$parameters=[]){
        $model_common = new \Model_Common();
        $model_common->TransStart();
        $result = call_user_func($callback,$parameters); //執(zhí)行回調(diào)函數(shù)
        if($this->commit){
            $model_common->Commit();
        }else{
            $model_common->RollBack();
        }
        return $result;
    }
}

應(yīng)用業(yè)務(wù)類

<?php

namespace Tests\Feature;

use Tests\TestBaseCase;
use Tests\Data\OrderVehicleJson;

class OrderVehicleNewTest extends TestBaseCase
{
    protected $commit = false;

    protected $ret = 0;


    /**
     * @notes: 業(yè)務(wù)線數(shù)據(jù)
     * @author: jackin.chen
     * @time: 2022/11/8 16:35
     * @function: testBusinessList
     */
    public function testBusinessList()
    {
        $response = $this->call('order_vehicle_new/business',[]);
        $this->assertJsonString($response,['ret' => $this->ret]);
        $this->assertNotEmpty($response['data']);
    }


    /**
     * @notes: 查詢數(shù)據(jù)供給器
     * @return \int[][]
     * @author: jackin.chen
     * @time: 2022/10/20 14:17
     * @function: additionProvider
     */
    public function vehicleStandardProvider()
    {
        //類型、國標(biāo)ID、期望值
        return array(
            array(\Input_OrderVehicleNew::IS_STATUS1, \Input_OrderVehicleNew::VEHICLE_ATTR0,$this->ret),
            array(\Input_OrderVehicleNew::IS_STATUS1, \Input_OrderVehicleNew::VEHICLE_ATTR1,$this->ret),
            array(\Input_OrderVehicleNew::IS_STATUS2, \Input_OrderVehicleNew::VEHICLE_ATTR0,$this->ret),
            array(\Input_OrderVehicleNew::IS_STATUS2, \Input_OrderVehicleNew::VEHICLE_ATTR1,$this->ret)
        );
    }


    /**
     * @notes: 所屬國標(biāo)訂單車型
     * @param $vehicle_attr_type
     * @param $status
     * @param $expected
     * @author: jackin.chen
     * @time: 2022/11/8 16:41
     * @function: testVehicleStandardList
     * @dataProvider vehicleStandardProvider
     */
    public function testVehicleStandardList($vehicle_attr_type,$status,$expected)
    {
        $params =  [
            'vehicle_attr_type'=>$vehicle_attr_type,
            'status'=>$status
        ];
        $response = $this->call('order_vehicle_standard/a_get_list_all',$params);
        $this->assertJsonString($response,['ret' => $expected]);
        $this->assertNotEmpty($response['data']);
    }


    /**
     * @notes: 獲取關(guān)聯(lián)國標(biāo)車型的圖片信息二級下拉框信息
     * @author: jackin.chen
     * @time: 2022/11/9 11:05
     * @function: testGetImgOption
     */
    public function testGetImgOption()
    {
        $params =  [];
        $response = $this->call('order_vehicle_standard/a_get_img_option',$params);
        $this->assertJsonString($response,['ret' => $this->ret]);
        $this->assertNotEmpty($response['data']);
    }


    /**
     * @notes:
     * @param $params
     * @author: jackin.chen
     * @time: 2022/11/9 13:53
     * @function: testOrderVehicleNewAdd
     */
    public function testOrderVehicleNewAdd()
    {
        $json = file_get_contents(__DIR__.'/../Data/add_order_vehicle.json');
        $params = json_decode($json,true);
        $response = $this->call('order_vehicle_new/add_order_vehicle',$params);
        $this->assertJsonString($response,['ret' => $this->ret]);
        $this->assertNotEmpty($response['data']);
    }


}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容