国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

寫一個“特殊”的查詢構造器 - (八、單元測試、收尾工作)

Steve_Wang_ / 2781人閱讀

摘要:單元測試的好處是給開發人員的,并不是給機器的。對于查詢構造器這個項目,我們可以讓其在遠程運行環境安裝相關數據庫軟件,執行數據表建立,數據導入,執行單元測試等操作。查詢構造器的完整代碼查詢構造器的單元測試完整代碼。

debug 模式

對查詢構造器進行調試并不難,從其構造 SQL -> 數據綁定 -> SQL 執行的過程中就能發現,要方便調試,只要可以觀察以下信息:

構造的 SQL

綁定的數據

PDO 提供了一個方便的 debug 方法 PDOStatement::debugDumpParams() 來打印 SQL 和綁定的數據。我們就使用它來做 debug 的工作。

在基類添加 _debug 屬性和 withDebug() 方法:

protected $_debug = FALSE;

...

public function withDebug()
{
    $this->_debug = TRUE;
    // 方便鏈式調用,返回當前實例
    return $this;
}

修改 _execute() 方法:

protected function _execute()
{
    try {
        $this->_wrapPrepareSql();
        $this->_pdoSt = $this->_pdo->prepare($this->_prepare_sql);
        $this->_bindParams();
        $this->_pdoSt->execute();
        $this->_reset();  
        // 如果是 debug 模式,則打印相關信息
        if($this->_debug) {
            $this->_pdoSt->debugDumpParams(); // 打印 debug 信息
            $this->_debug = FALSE; // debug 只在當此訪問有效,打印完就關閉
        }
    } catch (PDOException $e) {
        // when time out, reconnect
        if($this->_isTimeout($e)) {
            $this->_closeConnection();
            $this->_connect();
            // retry
            try {
                $this->_wrapPrepareSql();
                $this->_pdoSt = $this->_pdo->prepare($this->_prepare_sql);
                $this->_bindParams();
                $this->_pdoSt->execute();
                $this->_reset();
                // 如果是 debug 模式,則打印相關信息
                if($this->_debug) {
                    $this->_pdoSt->debugDumpParams(); // 打印 debug 信息
                    $this->_debug = FALSE; // debug 只在當此訪問有效,打印完就關閉
                }
            } catch (PDOException $e) {
                throw $e;
            }

        } else {
            throw $e;
        }
    }

}

這樣,在任何一個語句構造過程中使用 withDebug() 方法 (在 get()、row() 等取結果的方法調用之前),就能打印出 debug 的信息。

注:因為我在常駐內存模式下使用,所以選擇直接打印到 stdout 中,這樣可以直接在終端界面上調試。傳統 web 模式中可以使用 Output Control 系列函數 來獲取 debug 信息。
單元測試 單元測試的必要性

從項目的角度看:

當項目的規模很小的時候,單元測試沒什么用。但是如果是寫底層框架或者項目發展到一定的規模時,單元測試對于提高生產力有很明顯的貢獻。

從程序設計的角度上看:

單元測試可以讓你更好的拆分程序為最小單元,幫助你更好的解耦。

單元測試的好處是給開發人員的,并不是給機器的。

拿我們編寫的查詢構造器為例,where()、get() 等方法依賴了很多底層的方法,底層方法之間也有互相的調用。

情況一:你要為一個底層方法添加功能,改完后如何判斷是否會影響上層調用呢?把所有調用它的方法都調用一遍看結果嗎?不用,只需使用單元測試,確定這個方法的輸入輸出、可能的運行情況和邊界狀態,即保證最小單元可用。只要通過單元測試,則這個方法就沒有問題 (當然這里的程序結構必須設計合理、測試必須準確有效)。

情況二:有一天,你想為你的查詢構造器再支持一個新的數據庫,這個數據庫的驅動類繼承自基類。但是你不清楚基類的這些方法是否對新的數據庫還有效 (比如 postgresql 中 lastInsertId 的不同),要把所有方法跑一遍嗎?不用,你只需事先把這些通用方法寫好單元測試,把驅動類換作新數據庫的驅動類執行單元測試即可,跑一遍你就會發現有哪些方法是有問題的。

情況三:和情況一類似,當一個方法出 bug 時,你并不能馬上定位此 bug 出在此方法還是此方法依賴的方法上。而且當你定位了 bug 并進行修復時,發現其它方法因為修復出現了新的 bug,又是一輪 bug 查找。使用單元測試后,每次有修改后,都跑一遍單元測試,可以很快的發現此次修改對整個程序的影響,為我們節省很多時間。

當然,單元測試中還有 stub、mock 之類的模式可以很好的解決依賴不確定、難重現的問題,這里不做重點,我們就不多說了。

使用 PHPUnit

到現在之前,我們都是使用 test/test.php 這個文件寫一些測試,這種簡單的方式雖然做一些簡單測試沒有問題,但是完成單元測試就要大費周章了。而 PHP 有著名的單元測試框架 PHPUnit,能很好的完成我們進行測試的需求,所以單元測試這塊兒,我們使用 PHPUnit。

安裝 PHPUnit

PHPUnit 的安裝很簡單,在項目中執行:

composer require "phpunit/phpunit" "~4.0"
composer require "phpunit/dbunit" "~2.0" 
注:我們的測試需要連接數據庫,所以要安裝 dbunit

現在在項目目錄下的 test 文件夾中新建以 Test.php 結尾的測試文件,命令行運行 phpunit 即可運行測試。【1】

單元測試的編寫

單元測試的代碼簡單、代碼量大,我就不在這里展示了,所有的測試代碼見 WorkerF - tests - DB。

當然,對于這個單元測試,還是要做一些說明的。

單元測試的結構:

項目目錄/
    test/
        PDODML.php
        PDODQL.php
        MysqlPDODMLTest.php
        MysqlPDODQLTest.php
        PgsqlPDODMLTest.php
        PgsqlPDODQLTest.php
        SqlitePDODMLTest.php
        SqlitePDODQLTest.php
        PDODriverTest.php
        test.xml
        testMysql.sql
        testPgsql.sql
        testSqlite.sql

PDODML.php 和 PDODQL.php 文件:

首先看 PDODML 和 PDODQL 類,包含了通用的 DQL 和 DML 方法的測試,通過原生 PDO 執行 SQL 得出的結果和查詢構造器構造執行得出的結果相比較。

MysqlPDODMLTest.php、MysqlPDODQLTest.php 等數據庫開頭測試文件:

MysqlPDODMLTest 繼承自 PDODML,MysqlPDODQLTest 繼承自 PDODQL,Pgsql 和 Sqlite 同樣道理。

MysqlPDODMLTest、MysqlPDODQLTest 這些測試類中使用 phpunit 的 setUpBeforeClass() 方法和 dbunit 的 getConnection() 方法等創建了一個全局可用的數據庫連接,方便測試時對數據庫的訪問。

test.xml:

test.xml 中寫好了 dbunit 要求的固定格式的模擬數據,用來測試時自動填充、恢復數據表 (因為 insert、update 等會更改數據表,這也是要用 dbunit 的原因)。

PDODriverTest.php:

里面包含了對基類所有方法的測試。這里要說明一下,基類中有很多 protected 方法,我的測試方案是寫一個新的類,繼承自基類,然后新建 public 方法包裹要測試的 protected 方法,對新建的 public 方法進行測試,即達到了測試 protected 方法的目的。

這個文件中的測試更多是測試各個方法構造的 SQL 字符串是否符合預期,使用的正則匹配斷言比較多。

sql 文件:

幾個數據庫測試表的建表 sql。

本地測試

想要在你的本地跑這些測試的話,打開 MysqlPDODMLTest.php、MysqlPDODQLTest.php 等數據庫開頭的文件,把數據庫配置中的 username、password、dbname 等改成你自己的即可。

集成測試 Travis CI 什么是 Travis CI?

Travis CI 提供的是持續集成服務(Continuous Integration,簡稱 CI)。它綁定 Github 上面的項目,只要有新的代碼,就會自動抓取。然后,提供一個運行環境,執行測試,完成構建,還能部署到服務器。【2】

持續集成指的是只要代碼有變更,就自動運行構建和測試,反饋運行結果。確保符合預期以后,再將新代碼"集成"到主干。【2】

持續集成的好處在于,每次代碼的小幅變更,就能看到運行結果,從而不斷累積小的變更,而不是在開發周期結束時,一下子合并一大塊代碼。【2】

使用 Travis CI

如果你要將項目推到 Github 上,可以接入 Travis CI。通過編寫 .travis.yml 配置文件,可以實現遠程運行環境的語言多版本切換、軟件安裝、腳本執行等操作。

對于查詢構造器這個項目,我們可以讓其在遠程運行環境安裝相關數據庫軟件,執行數據表建立,數據導入,執行單元測試等操作。

我的框架項目 WorkerA 就集成了 Travis CI ,相關配置見 WorkerF - .travis.yml,感興趣的可以了解下。

注釋

PHP 中對方法的注釋一是為了提示,二是為了生成文檔。我這里的注釋寫法是標明功能、參數、返回值和拋出的異常。一個清晰好懂的注釋對于項目來說還是很必要的。

例如:

/**
 * get paginate data
 *
 * @param  int $step
 * @param  int $page
 * @return  array
 * @throws  PDOException
 */
public function paginate($step, $page = NULL)
{
    ...
}
尾聲

一個查詢構造器的創建到此結束,希望對大家有用。如果發現文中的書寫和思路有錯誤,或者對此項目有什么好的建議的話,歡迎提出。對文中的解釋有不解的地方,也歡迎提問。

查詢構造器的完整代碼:WorkerF - DB

查詢構造器的單元測試完整代碼:WorkerF - tests - DB。

參考

【1】PHPUnit Doc

【2】持續集成服務 Travis CI 教程 - 阮一峰

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/28715.html

相關文章

  • 一個特殊查詢造器 - (前言)

    摘要:而在項目開發中,我們想要的是一個更好用的可維護的工具,此時,對代碼的封裝模塊化就顯得尤為重要,于是出現了兩種方案查詢構造器,對象關系映射。典型環境下按照一般的查詢構造器處理就行。 文章目錄 寫一個特殊的查詢構造器 - (前言) 寫一個特殊的查詢構造器 - (一、程序結構,基礎封裝) 寫一個特殊的查詢構造器 - (二、第一條語句) 寫一個特殊的查詢構造器 - (三、條件查詢) 寫一個特殊...

    GitChat 評論0 收藏0
  • 分享一下 軟件測試面試歷程和套路,真很實在

    摘要:軟件測試自學秘訣面試失敗一天,心態穩的一批,因為面試的全是外包人事幫我聯系的公司,工資全都是一萬以上,之前只有四五千的自己根本不覺得自己能勝任。 個人是去年年底零基礎轉行,兩三千培訓費學出來,學完后也是稀里糊涂,僅是知道功能測試就是找問題,其他接口,性能,數據庫,python基礎,虛擬機搭建網站都實現了課程展示那樣。面試資...

    Lyux 評論0 收藏0
  • 一個特殊查詢造器 - (二、第一條語句)

    摘要:注在常駐內存單例模式下,這種多次用一個類進行查詢的情形很常見。斷線重連對于典型環境而言,一次的查詢已經隨著的請求而結束,的垃圾回收功能會回收一次請求周期內的數據。但在常駐內存的環境下,尤其是單例模式下,數據庫驅動類可能一直在內存中不被銷毀。 構造、執行第一條語句 上一篇完成了代碼結構的搭建和 PDO 的基礎封裝,這一篇我們來講如何構造一個最基本的 SQL 語句,并執行得到結果。 que...

    dadong 評論0 收藏0
  • JavaScript 編程精解 中文第三版 、Bug 和錯誤

    摘要:幸運的是,使用符號創建的構造器,如果在不使用來調用,則始終會報錯,即使在非嚴格模式下也不會產生問題。 來源:ApacheCN『JavaScript 編程精解 中文第三版』翻譯項目原文:Bugs and Errors 譯者:飛龍 協議:CC BY-NC-SA 4.0 自豪地采用谷歌翻譯 部分參考了《JavaScript 編程精解(第 2 版)》 調試的難度是開始編寫代碼的兩倍。 因此,如...

    wujl596 評論0 收藏0
  • 一個特殊查詢造器 - (六、關聯)

    摘要:雖然現在這樣的情況已經很少,但是對于查詢構造器而言,還是要提供一個方便的方法來對表前綴進行設置,特別是當你沒有權限修改表名的時候。所以我們將表前綴作為一個配置參數傳入查詢構造器,在查詢構造器的底層進行自動前綴添加。 關聯查詢是關系型數據庫典型的查詢語句,根據兩個或多個表中的列之間的關系,從這些表中查詢數據。在 SQL 標準中使用 JOIN 和 ON 關鍵字來實現關聯查詢。 Join 子...

    rainyang 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<