2013-04-24 42 views
0

比方說,我有一個小的類來處理到MySQL數據庫的連接:測試方法行爲類似的getter/setter方法,但更象是工廠

class myDatabaseHandler{ 

    private $_databases; 

    public function addDatabase($name, $dsn, $username, $password){ 
    $this->_databases[$name] = array('dsn' => $dsn, 'username' => $username, 'password' => $password); 
    return true; 
    } 

    public function getDatabase($name){ 

    $connectionInfo = $this->_databases[$name]; 
    $database = new Database($connectionInfo['dsn'], $connectionInfo['username'], $connectionInfo['password']); 

    $database->doSomeSetup(); 
    $database->attachMoreThings(); 

    return $database; 
    } 
} 

我想單元測試這2種方法:

class myDatabaseHandlerTest extends \PHPUnit_Framework_TestCase 
{ 
    public function testAddDatabase(){ 

    } 

    public function testGetDatabase(){ 

    } 
} 

我如何測試這兩種方法?如果我addDatabase(),最多它會返回一個Boolean告訴我操作成功。由於它寫入私有屬性,我無法確認是否正確寫入了正確的數據。

我覺得利用getDatabase()獲得一個數據庫對象返回和測試針對它是不完全理想的,因爲我需要公開dsnusernamepassword只是用於測試的緣故。另外,Database對象可能會將這些值修改爲它使用的格式,所以我需要存儲原始值以進行測試。

解決此問題的最佳方法是什麼?

回答

0

當您嘗試構建在同一地點使用對象時,測試肯定會變得棘手。在這種情況下,您正在構建Database並在您的getDatabase($name)方法中調用方法。這使得模擬幾乎不可能,例如,爲了獲得體面的覆蓋範圍,您的測試需要測試Database類所提供的功能,以確保系統按預期行事。

更好的方法可能是使用合適的工廠作爲依賴項。

interface iDatabaseFactory 
{ 
    public function buildDatabase($dsn, $username, $password); 
} 

然後,你可以嘲笑了數據庫工廠和數據庫實例本身,以驗證它是兩個構建正確和正確初始化:

class MockDatabaseFactory implements iDatabaseFactory 
{ 
    public $databaseParams = array(); 
    public $databaseToReturn = NULL; 

    public function buildDatabase($dsn, $username, $password) 
    { 
     $this->databaseParams['dsn'] = $dsn; 
     $this->databaseParams['username'] = $username; 
     $this->databaseParams['password'] = $password; 
     return $this->databaseToReturn; 
    } 
} 

class myDatabaseHandlerTest extends PHPUnit_Framework_TestCase 
{ 
    public function testAddAndGetDatabaseUsesCorrectDbParameters(){ 
     $mockDatabaseFactory = new MockDatabaseFactory(); 
     $dbHandler = new myDatabaseHandler($mockDatabaseFactory); 

     // implement MockDatabase according to your interface 
     $mockDatabase = new MockDatabase(); 
     $mockDatabaseFactory->databaseToReturn = $mockDatabase; 

     $dbHandler.addDatabase("some name", "some dsn", 
           "some username", "pa$$w0rd"); 
     $builtDatabase = $dbHandler.getDatabase("some name"); 

     $this->assertEquals($mockDatabase, $builtDatabase); 
     $dbParams = $mockDatabaseFactory->databaseParams; 
     $this->assertEquals("some dsn", $dbParams['dsn']); 
     $this->assertEquals("some username", $dbParams['username']); 
     $this->assertEquals("pa$$w0rd", $dbParams['password']); 
    } 

    public function testAddAndGetDatabaseInitializesDb(){ 
     $mockDatabaseFactory = new MockDatabaseFactory(); 
     $dbHandler = new myDatabaseHandler($mockDatabaseFactory); 

     $mockDatabase = new MockDatabase(); 
     $mockDatabaseFactory.setDatabaseToBuild($mockDatabase); 

     $dbHandler.addDatabase("name", "dsn", "user", "pass"); 
     $builtDatabase = $dbHandler.getDatabase("some name"); 

     $this->assertTrue($mockDatabase->doSomeSetupWasCalled); 
     $this->assertTrue($mockDatabase->attachMoreThingsWasCalled); 
    } 
}