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: Testcase Class Per Class

04.13.2011
| 4846 views |
  • submit to reddit

We have many, many tests in our suites. Each of them is a single method, starting with the 'test' prefix. But where do we put them? In several Testcase Classes.

There are several alternatives for choosing how to name the Testcase Classes and how many should be created. These patterns can be used in different parts of your suite, and today we will see the most natural one: Testcase Class per Class.

"When" is the right question

According to this pattern, you should create a Testcase Class for each class in the production code that you want to test. The tests in this class will exercise the production code class, as much as possible by maintaining an object in isolation, and inserting Test Double where necessary.

This pattern requires a clear correspondence between tests and classes: thus it is "adapt" for unit tests and less for functional and integration one. For end-to-end tests or acceptance tests written in the domain language, the simmetry is often lost.

For example, when you're testing a model class, it's likely that you can find test scenarios that works well on an object of the class in isolation. When you're testing the user interface instead, you do not have a strict correspondence between test scenarios and production classes (although a loose correspondence can be made with controllers in MVC frameworks).

Implementation

Usually the naming convention followed for this pattern on a medium/large scale is to replicate the hierarchical structure of the production code:
library/
    My/
        CoolClass.php
tests/
    My/
        CoolClassTest.php

CoolClassTest contains in this case a My_CoolClassTest (or My\CoolClassTest if you use namespaces) class extending PHPUnit_Framework_TestCase or a subclass of it.

This simple convention aids you in mapping from one test class to the related production one, and vice versa; even when thousands of classes are involved the mapping remain straightforwards, ans we can say it is O(1). Zend Framework 1 for example mostly uses this pattern and this convention.

If you have always used this pattern, you probably think that this is the norm. It is, but there are alternatives which trades off the simmetry of code and tests in order to build more cohesive tests (for example when a Testcase Class grows too much, it can be broken down in smaller classes which do not corresponde anymore to different production classes.)

Example

In this series, we presented mostly examples as unit tests, since they are the simplest to setup and transport to your computer for running. As so, most of the various pieces of code follows the convention of Testcase Class per Class.

Thus the sample code of today is more related to the structure of the tests than to their content. The folder contains two parallel trees of production code classes and test cases. For each class:

<?php
class MyClass
{
}

you have a Testcase similarly named:

<?php
// in reality this would be done via autoloading and bootstrap file
require_once __DIR__ . '/../classes/MyClass.php';

class MyClassTest extends PHPUnit_Framework_TestCase
{
    public function testCanInstanceAnObjectOfTheClassUnderTest()
    {
        $object = new MyClass;
        $this->assertTrue($object instanceof MyClass);
    }
}

And if the class is under a hierarchy:

<?php
class Component_OtherClass
{
}

the Testcase follows the same hierarchy in order to be found easily:

<?php
// in reality this would be done via autoloading and bootstrap file
require_once __DIR__ . '/../../classes/Component/OtherClass.php';

class Component_OtherClassTest extends PHPUnit_Framework_TestCase
{
    public function testCanInstanceAnObjectOfTheClassUnderTest()
    {
        $object = new Component_OtherClass;
        $this->assertTrue($object instanceof Component_OtherClass);
    }
}

You can take a look at the Github repository to see the folder structure.

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.)