假设我有一个处理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(){
}
}
我如何测试这两种方法?如果我addDatabase()
,最多会返回Boolean
告诉我操作成功。由于它写入私有属性,我无法确认是否确实写入了正确的数据。
我觉得使用getDatabase()
来获取数据库对象并对其进行测试并不完全理想,因为我需要公开dsn
,username
和password
只是为了测试。此外,Database
对象可能会将这些值修改为它使用的格式,因此我需要存储原始值以供测试。
解决此问题的最佳方法是什么?
答案 0 :(得分: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);
}
}