Testing PHP PDO Error Handling Code

Testing code can be hard. And because its hard, sometimes we don’t bother to do it.

Ironically the code that can be hardest to test is code that handles errors: when your code works, hitting a catch { ... } block is actually kind of hard! You need to force the failure.

You might be tempted to think well if my code works correctly, I don’t have to worry about it. OK, hotshot. But you can’t control every factor that might cause your code to fail.

Consider database code. You need to know how your code reacts when the database connection fails. A failed database connection isn’t something that’s easy to automate in a test. And if it’s not easy, and it’s not automatic, there’s a pretty good chance we won’t bother testing it.

Well good news, fellow lazy developer: you can automate it. Easily. At least in PHP 7.

Introducing ShittyPDO

If you are working with PDO database connection objects, just extend PDO with some bad behavior, and use that to talk to your models. I call this methodShittyPDO. You can make this a proper class and use it anywhere, but I usually I just create an anonymous class as follows:

<?php$pdo = new class extends PDO {    // Because we don't want to worry about connection strings:
public function __construct() { }
public function prepare($statement, $options = null)
{
throw new PDOException('Acting kind of shitty');
}
}

What we have above is a PDO object that is going to shit the proverbial bed when we call prepare(). How is this useful? Consider the following hypothetical model class.

<?phpclass UserModel
{
protected $pdo;
public function __construct(PDO $pdo)
{
$this->pdo = $pdo;
}
public function read(int $userId) : User
{
try {
$statement = $this->pdo->prepare('
SELECT * FROM Users
WHERE userId = :userId;
');
$statement->execute(); return $this->translate(
$statement->fetchAll(
PDO::FETCH_ASSOC
)
);
} catch(PDOException $pdoException) {
// How do we test this?
throw new ModelException(
'Real bad SQL related things going on');
);
}
}
public function translate(array $result) : User
{
// Lets assume this converts a result to a
// User object
}
}

Above we have a typical model backed by a PDO connection. The catch block doesn’t do anything amazing: it throws a different kind of Exception. But let’s say we want to verify it’s actually throwing the sort of Exception we think it is, or let’s pretend that error-handling code is doing something a little more magical. How do we reliably test it?

Consider the following PHPUnit test.

class PrinterModelTest extends TestCase
{
public function testModelException()
{
// Return the extended PDO object from above.
$pdo = $this->getShittyPDO();
$model = new UserModel($pdo); $this->expectException(ModelException::class);
$model->read(12);
}
}

The testModelException() test will create an instance of the model using the tricked-out PDO object that will intentionally fail when the model calls prepare(). By injecting a designed to fail connection object we can easily cause the catch { ... } to be invoked and test the code within it.

Reich Web Consulting

Written by

Purveyor of fine web creations. Former tech support geniuses. Occasional spouter of opinions on topics of politics and ethics.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade