Sunday, February 07, 2010

Test suites and php namespaces

Php namespaces, introduced with the 5.3 release, are a great tool to stop writing very long class names. Importing class names via use statements makes you able to refer to classes via their base name, for example by writing:
use NakedPhp\MetaModel\NakedObject;
you will be able to use the name NakedObject in method definitions and instantiations in the rest of the script.
In test code, however, you will often have to import the classes under test and the involved abstractions to define some stubs. If the primary test case class for NakedBareObject is NakedPhp\Tests\ProgModel\NakedBareObjectTest, an use statement in its source file such as:
use NakedPhp\ProgModel\NakedBareObject;
is mandatory.

My suggestion is to organize code in parallel class hierarchies for test case classes and production classes, so that the test suite's classes are not in the same folders as their SUTs, but they reside in the same namespace at runtime. This is a diffused practice in the JUnit world and it is even listed in the JUnit faq.
Consider as an example the NakedPhp directory structure:
library/ and tests/ are the two folders that contain production code and test cases in parallel hierarchies. Autoloading works simply by adding to the include_path both directories.
The test case classes have the suffix Test added to the name. The test case class for NakedPhp\ProgModel\NakedBareObject is NakedPhp\ProgModel\NakedBareObjectTest.
The basic assumption of this directory structure is thinking of namespaces as packages, or reusable modules, whose dependencies should be limited as much as possible. Considering the NakedPhp repository, I am refactoring the original NakedPhp\Metadata namespace, splitting it in two parts: NakedPhp\MetaModel and NakedPhp\ProgModel, with the latter's classes having dependencies on the former, which contains primarily interfaces. I am also moving the classes which disturb the cohesion of these two namespaces in other ones which already depends on NakedPhp\MetaModel: high cohesion of single software modules is obtained by keeping together strongly coupled classes, so that changes in one of them do not propagate all over the application.

Here are some advantages of the parallel hierarchies paradigm:
  • when you're testing the SUT you don't have to import it, since the two classes are in the same namespace (but in different folders, so test cases do not clutter your production code directories.)
  • when you're referencing classes or interfaces from the same namespace, treated here as a package, you still do not have to import them. This case will be very frequent as good engineered classes do not have different responsibilities but delegate part of their operations to collaborators.
  • when you're using classes from another namespace, this is the signal that you are establishing coupling to that namespace. This is not necessarily bad. Use statements become not a boring and repetitive declaration to write, but the signpost of an external dependency towards another module of your application. Mutual or unnecessary dependencies between namespaces are smells that are thus noticed quickly.


alberto said...

Test class per Class leads to bad tests, IMHO.

I prefer grouping them by fixture or feature.

Giorgio said...

For *unit* testing I prefer single test cases, while for bigger scale testing multiple fixtures are necessary. Of course with proper naming you can still put multiple test cases in the same namespace of the Production class, but for functional and integration test this is less important.