0

假设我有一个处理与 MySQL 数据库的连接的小类:

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

我想对这两种方法进行单元测试:

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

    }

    public function testGetDatabase(){

    }
}

我该如何测试这两种方法?如果 I addDatabase(),最多它会返回一个Boolean告诉我操作成功。由于它写入私有财产,我无法确认确实写入了正确的数据。

我觉得使用getDatabase()来获取数据库对象并对其进行测试并不完全理想,因为我需要公开dsnusername并且password只是为了测试。此外,Database对象可能会将这些值修改为它使用的格式,因此我需要存储原始值仅用于测试。

解决这个问题的最佳方法是什么?

4

1 回答 1

0

当您尝试在同一个地方构造使用对象时,测试肯定会变得棘手。在这种情况下,您既要在方法中构造 aDatabase又要在其上调用方法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);
    }
}
于 2013-04-24T04:29:09.740 回答