PHPUnit 數(shù)據(jù)庫(kù)測(cè)試用例的配置

2018-02-24 15:41 更新

PHPUnit 數(shù)據(jù)庫(kù)測(cè)試用例的配置

一般而言,使用 PHPUnit 時(shí),測(cè)試用例都是按如下方式擴(kuò)展自 PHPUnit_Framework_TestCase 類(lèi):

<?php
class MyTest extends PHPUnit_Framework_TestCase
{
    public function testCalculate()
    {
        $this->assertEquals(2, 1 + 1);
    }
}
?>

如果測(cè)試代碼用到了數(shù)據(jù)庫(kù)擴(kuò)展模塊,那么建立的過(guò)程就會(huì)更復(fù)雜一些,需要擴(kuò)展另一個(gè)抽象 TestCase 類(lèi),它要求實(shí)現(xiàn)兩個(gè)抽象方法,getConnection()getDataSet()

<?php
class MyGuestbookTest extends PHPUnit_Extensions_Database_TestCase
{
    /**
     * @return PHPUnit_Extensions_Database_DB_IDatabaseConnection
     */
    public function getConnection()
    {
        $pdo = new PDO('sqlite::memory:');
        return $this->createDefaultDBConnection($pdo, ':memory:');
    }

    /**
     * @return PHPUnit_Extensions_Database_DataSet_IDataSet
     */
    public function getDataSet()
    {
        return $this->createFlatXMLDataSet(dirname(__FILE__).'/_files/guestbook-seed.xml');
    }
}
?>

實(shí)現(xiàn) getConnection()

為了讓清理與載入基境的功能正常運(yùn)作,PHPUnit 數(shù)據(jù)庫(kù)擴(kuò)展模塊需要用 PDO 庫(kù)來(lái)實(shí)現(xiàn)跨供應(yīng)商抽象訪(fǎng)問(wèn)數(shù)據(jù)庫(kù)連接。重要的是要注意到,使用 PHPUnit 的數(shù)據(jù)庫(kù)擴(kuò)展模塊并不要求應(yīng)用程序本身基于PDO,PDO連接僅僅用于清理和建立基境。

在之前的例子里,我們?cè)趦?nèi)存中創(chuàng)建 Sqlite 數(shù)據(jù)庫(kù)并建立了連接,將此連接傳遞給 createDefaultDBConnection 方法,這個(gè)方法將 PDO 實(shí)例和第二參數(shù)(數(shù)據(jù)庫(kù)名)包裝在一個(gè)非常簡(jiǎn)單的數(shù)據(jù)庫(kù)連接抽象層中,這個(gè)抽象層的類(lèi)型是 PHPUnit_Extensions_Database_DB_IDatabaseConnection。

“使用數(shù)據(jù)庫(kù)連接”一節(jié)解說(shuō)了這個(gè)接口的API以及如何充分利用它們。

實(shí)現(xiàn) getDataSet()

getDataSet() 方法定義了在每個(gè)測(cè)試執(zhí)行之前的數(shù)據(jù)庫(kù)初始狀態(tài)應(yīng)該是什么樣。數(shù)據(jù)庫(kù)的狀態(tài)通過(guò)由 PHPUnit_Extensions_Database_DataSet_IDataSet 所代表的 DataSet(數(shù)據(jù)集)和由 PHPUnit_Extensions_Database_DataSet_IDataTable所代表的 DataTable(數(shù)據(jù)表)這兩個(gè)概念進(jìn)行抽象。下一節(jié)將詳細(xì)講述這些概念是如何運(yùn)作的以及在數(shù)據(jù)庫(kù)測(cè)試中使用它們有什么好處。

對(duì)于具體實(shí)現(xiàn),只需要知道 setUp() 中會(huì)調(diào)用一次 getDataSet() 方法來(lái)接收基境數(shù)據(jù)集并將其插入數(shù)據(jù)庫(kù)。在范例中使用了工廠方法 createFlatXMLDataSet($filename),它代表一個(gè)用 XML 表示的數(shù)據(jù)集。

數(shù)據(jù)庫(kù)構(gòu)架(DDL)怎么辦?

PHPUnit 假設(shè)在測(cè)試運(yùn)行之前數(shù)據(jù)庫(kù)以及其中的所有表(table)、觸發(fā)器(trigger)、序列(Sequence)和視圖(view)都已經(jīng)創(chuàng)建好。這意味著開(kāi)發(fā)者必須在運(yùn)行測(cè)試套件之前確保數(shù)據(jù)庫(kù)已經(jīng)正確建立。

有幾種方法來(lái)達(dá)成這個(gè)數(shù)據(jù)庫(kù)測(cè)試的先決條件。

  1. 如果使用的是持久化數(shù)據(jù)庫(kù)(不是 Sqlite Memory),可以很輕松地用 phpMyAdmin(針對(duì)MySQL)之類(lèi)的工具來(lái)一次性建立數(shù)據(jù)庫(kù),并在每個(gè)測(cè)試中復(fù)用這個(gè)數(shù)據(jù)庫(kù)。

  2. 如果使用的是諸如 Doctrine 2Propel 這樣的庫(kù),可以用它們的API來(lái)在測(cè)試運(yùn)行前一次性建立所需的數(shù)據(jù)庫(kù)??梢岳?PHPUnit 的引導(dǎo)和配置 功能來(lái)在每次測(cè)試運(yùn)行時(shí)執(zhí)行這些代碼。

小建議:使用你自己的抽象數(shù)據(jù)庫(kù) TestCase 類(lèi)

從前面的實(shí)現(xiàn)范例中容易發(fā)現(xiàn) getConnection() 方法是相當(dāng)穩(wěn)定的,可以在不同的數(shù)據(jù)庫(kù)測(cè)試用例中重用。另外,為了保持測(cè)試的性能良好和數(shù)據(jù)庫(kù)的開(kāi)銷(xiāo)較低,可以對(duì)代碼進(jìn)行一點(diǎn)重構(gòu),來(lái)為應(yīng)用程序形成一個(gè)通用的抽象測(cè)試用例,同時(shí)依然可以為每個(gè)具體測(cè)試用例指定不同的數(shù)據(jù)基境:

<?php
abstract class MyApp_Tests_DatabaseTestCase extends PHPUnit_Extensions_Database_TestCase
{
    // 只實(shí)例化 pdo 一次,供測(cè)試的清理和裝載基境使用
    static private $pdo = null;

    // 對(duì)于每個(gè)測(cè)試,只實(shí)例化 PHPUnit_Extensions_Database_DB_IDatabaseConnection 一次
    private $conn = null;

    final public function getConnection()
    {
        if ($this->conn === null) {
            if (self::$pdo == null) {
                self::$pdo = new PDO('sqlite::memory:');
            }
            $this->conn = $this->createDefaultDBConnection(self::$pdo, ':memory:');
        }

        return $this->conn;
    }
}
?>

這個(gè)例子里,數(shù)據(jù)庫(kù)連接信息硬編碼在 PDO 連接里了。PHPUnit 有另外一個(gè)絕妙的特性,可以讓這個(gè) TestCase 類(lèi)更加通用。通過(guò) XML 配置 可以為每個(gè)測(cè)試單獨(dú)配置數(shù)據(jù)庫(kù)連接信息。首先,在應(yīng)用程序的 tests/ 目錄下創(chuàng)建 “phpunit.xml” 文件,內(nèi)容大體是這樣:


<?xml version="1.0" encoding="UTF-8" ?>
<phpunit>
    <php>
        <var name="DB_DSN" value="mysql:dbname=myguestbook;host=localhost" />
        <var name="DB_USER" value="user" />
        <var name="DB_PASSWD" value="passwd" />
        <var name="DB_DBNAME" value="myguestbook" />
    </php>
</phpunit>

現(xiàn)在可以修改 TestCase 類(lèi)了,像這樣:

<?php
abstract class Generic_Tests_DatabaseTestCase extends PHPUnit_Extensions_Database_TestCase
{
    // 只實(shí)例化 pdo 一次,供測(cè)試的清理和裝載基境使用
    static private $pdo = null;

    // 對(duì)于每個(gè)測(cè)試,只實(shí)例化 PHPUnit_Extensions_Database_DB_IDatabaseConnection 一次
    private $conn = null;

    final public function getConnection()
    {
        if ($this->conn === null) {
            if (self::$pdo == null) {
                self::$pdo = new PDO( $GLOBALS['DB_DSN'], $GLOBALS['DB_USER'], $GLOBALS['DB_PASSWD'] );
            }
            $this->conn = $this->createDefaultDBConnection(self::$pdo, $GLOBALS['DB_DBNAME']);
        }

        return $this->conn;
    }
}
?>

現(xiàn)在可以從命令行界面以不同的配置來(lái)運(yùn)行數(shù)據(jù)庫(kù)測(cè)試套件了:

user@desktop> phpunit --configuration developer-a.xml MyTests/
user@desktop> phpunit --configuration developer-b.xml MyTests/

在開(kāi)發(fā)機(jī)上進(jìn)行開(kāi)發(fā)時(shí)能夠輕松的針對(duì)不同的目標(biāo)數(shù)據(jù)庫(kù)來(lái)運(yùn)行數(shù)據(jù)庫(kù)測(cè)試顯得非常重要。如果多個(gè)開(kāi)發(fā)人員在同一個(gè)數(shù)據(jù)庫(kù)連接上運(yùn)行數(shù)據(jù)庫(kù)測(cè)試,很容易因?yàn)楦?jìng)態(tài)而導(dǎo)致測(cè)試失敗。

以上內(nèi)容是否對(duì)您有幫助:
在線(xiàn)筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)