Agile Zone is brought to you in partnership with:

I am a programmer and architect (the kind that writes code) with a focus on testing and open source; I maintain the PHPUnit_Selenium project. I believe programming is one of the hardest and most beautiful jobs in the world. Giorgio is a DZone MVB and is not an employee of DZone and has posted 638 posts at DZone. You can read more from them at their website. View Full User Profile

Practical PHP Testing Patterns: Back Door Manipulation

11.17.2010
| 6480 views |
  • submit to reddit

In a test implementing Back Door Manipulation, you bypass the System Under Test to reach the resource it manipulates directly, with the goal of veryfing its behavior or to perform some other handy operations. In fact, there's more than one reasons why you may want to skip the SUT itself, but let's start with the example to make the pattern more clear.

In this example, a UsersRepository hides the database to provide the illusion of an in-memory collection of User objects, which will be persisted transparently. This is a classic Repository pattern and it's technically similar to a Data Access Object, but has different semantics which falls out of the scope of this article. A database is a classic example of resource handled by an object, but also manually accessible with minor inconveniences.

In the test, we skip the Repository to set up some data in the tables we want it to access, and also verify independently what it has accomplished:

<?php

class SharedFixtureDatabaseTest extends PHPUnit_Framework_TestCase
{
    /**
     * Back Door TearDown is automatic due to the connection being on an in-memory, fake database.
     */
    public function setUp()
    {
        $this->db = new PDO('sqlite::memory:');
        $this->db->exec('CREATE TABLE users (
                        id INT, 
                        name VARCHAR(255),
                        password VARCHAR(255),
                        PRIMARY KEY (id)
                   )');
        $this->sut = new UsersRepository($this->db);
    }

    public function testRetrievesUsers_BackDoorSetup()
    {
        $this->db->exec('INSERT (name, password) VALUES ("Giorgio", "example");');
        // ready to test UsersRepository::getAll()
    }

    public function testInsertsUsers_BackDoorVerification()
    {
        // test UsersRepository::add()
        $this->db->query('SELECT COUNT(*) FROM users');
        // assertions...
    }
}

/**
 * A sample System Under Test which requires a connection.
 */
class UsersRepository
{
    public function __construct(PDO $connection)
    {
        // ...
    }

    // ...
}

Let's talk about the advantages you get from Back Door Manipulation.
  • the tests will be more isolated from one another, and less brittle in general: if UsersRepository::add() breaks, only its own test will fail and signal you a focused problem. If we used the SUT itself to set up the database rows, a break in add(). This issue can be alleviated by the @depends $testMethodToObserve PHPUnit annotation, but not totally. For example, if we have breaks in both add() and delete() methods of a Repository, only the add() method would be executed and we would get to the delete() regression only after fixing the first one. If we set up the rows to delete via a Back Door, the delete() test never ceases to be executed.
  • Back Doors are faster than calling the SUT: querying directly a database does not involve the overhead of the Repository.
  • Back Doors are also simpler: the SUT may not even have the methods we want to set up or query its encapsulated state, and forcing the methods on it may result in a poor design.

Disadvantages

The problem with the overusage of this pattern is that you become dependent on the implementation details of the SUT. For example, if we wanted to switch the UsersRepository from a relational database implementation to a document-oriented one or to serialization (or even only to insert a cache), we will end up changing the tests too.

Variations

We encounter often different variations of this testing pattern. I'll list here the official names in the xUnit Patterns book, along with an example.

Back Door Setup involves the fixture setup of the test, and in the case of the database example the insertion of rows that the SUT can then manipulate.

Back Door Verification involves instead an independent verification of the resource state, usually via direct queries. Don't believe however SELECT queries are the only Back Door you can access. For example, SQL queries are too low-level to be handy for us and we do Back Door Verification with the Entity Manager (the ORM Facade) while testing something that interacts with the database, like a Repository.

Back Door Teardown is related to returning the shared resources in their original state, without relying on a possibly broken SUT to do it. Just yesterday we setup our Shared Fixture (database) tests to rollback every transaction still opened in the tearDown(). Thanks to this pattern, when a database-related object fails to close a transaction, only its correspondent test will fail, instead of each of the subsequent ones relying on a clean transaction state.

Published at DZone with permission of Giorgio Sironi, author and DZone MVB.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)