For practice i'm creating my own database wrapper and query builder. When creating a DatabaseConnection
object, a new PDO object is created in this object.
I have a Database
class which depends on the DatabaseConnection
object. This class builds the queries and executes them.
My DatabaseConnection
class looks like this:
use PDO;
class DatabaseConnection
{
/**
* @var PDO $pdo The PDO connection object
*/
private $pdo;
public function __construct(array $credentials)
{
# Logic with $credentials to check on data
$dsn = ...;
# Open the connection
$this->pdo = new \PDO($dsn, $credentials['username'], $credentials['password'], $options);
}
/**
* Checks whether the connection is open or closed
*
* @return bool Whether the connection is open or closed
*/
public function isConnected() : bool
{
return $this->pdo !== null;
}
/**
* Retrieves the PDO connection object
*
* @return PDO The PDO connection object
*/
public function getPDO() : PDO
{
return $this->pdo;
}
/**
* Closes the connection
*/
public function __destruct()
{
$this->pdo = null;
}
}
When testing this, I ran across the problem that I always have to have a indentical database with the same login credentials on every computer i test this on.
For my research, I found out that I can create a mock objects, by doing
$pdo = $this->getMockBuilder('PDO')
->disableOriginalConstructor()
->getMock();
The problem here is that I can't inject the $pdo
object into my DatabaseConnection
class.
What am I doing wrong and how can I test this class without using an actual database by mocking data?
For your mock, create a subtype of the DatabaseConnection, override the constructor and make the PDO object injectable. Then you can mock the PDO object and create the full mock for mocking operations.
Having "news" inside a constructor is a smell btw., your constructor should not do real work.
As you have found out while testing, this makes your type hard to test. Creating a mock on your own (by writing it out) can lighten up the darkened sky.
You might also not want to initialize the resources early, but connect to the database as late as possible. This would also move the new out of the constructor.