In my Beyond Frameworks talk, I explained how a component-based architecture can help answer some of the important (i.e. expensive!) questions you might face when creating long-lived apps that rely on a PHP framework. In this series of blog posts, I’m going to look at how to go about creating and working with components.

I’m now going under the bonnet of our components, and looking at the different file roles that the PEAR installer expects to find when we distribute our component as a PEAR-compatible package. One of the most important file roles allows you to ship your tests with your package – and it’s vital that this is something that you get in the habit of doing routinely.

Test Your Code, And Ship Your Tests

If you want other developers to re-use your code in their projects, it is essential that you earn their trust. Trust has to be earned over time, by establishing a track record of dependability. There are many things you need to do to establish such a reputation, such as semantic versioning to flag backwards-compatibility breaks, and writing unit tests to prove that your code works as expected.

Although the PEAR Installer has long supported shipping unit test code, to date the PHP community hasn’t really embraced this, and it is still very rare for a PEAR package to include unit tests when downloaded. This is also compounded by unfortunate legacy choices in some Linux distributions (ubuntu bug, fedora bug), where unit test code currently ends up being installed under the same directory tree as the main code from the PEAR packages – something that only really matters since the PHP Community started to adopt PSR-0 as the standard for autoloading.

What Are PHP Tests?

PHP tests (the ‘test’ file role supported by the PEAR Installer) are executable tests. There is currently no formal standard for these tests; however, PHPUnit has emerged as the community’s de facto standard for unit tests, and is the approach that the PHP components skeleton supports out of the box to make life much easier for you.

Just as important as shipping tests is making sure that it is extremely easy for someone who knows nothing about your code to safely and reliably execute any tests that you ship. The components skeleton handles much of this for you, by including a PHPUnit bootstrap.php file, and a build.xml file with full instructions on how to execute the tests.

However, it is important that you write your tests in a way that doesn’t rely on anything that your users won’t have installed or configured.

Where Do Tests Go Inside Your Component’s Structure?

If we look at the CommandLineLibrary component, you’ll find that the unit test files live in the src/tests/unit-tests/ folder:

Important notes:

  1. The folder structure underneath src/tests/unit-tests exactly matches the folder structure for both PHP scripts and PHP files under the src/ folder.
  2. Each unit test script is designed for PSR-0 autoloading, just like the PHP scripts that they test.
  3. Each unit test script ends in the word ‘Test’. This is a convention that is supported in IDEs such as Netbeans.

Where Does The PEAR Installer Install The Tests?

When you use the PEAR installer to install your component:

$ pear install phix/CommandLineLib

all of the test files get installed into /usr/share/php/tests/<package-name> on your computer:

The PEAR installer’s behaviour here is different to both command-line scripts and PHP code; the installer creates a sub-folder with the name of your package, and then installs your test files into this sub-folder, and not into the main test_dir folder. This isn’t a problem in practice, as long as you are aware of the different behaviour here.

The test file src/php/unit-tests/Phix_Project/CommandLineLib/CommandLineParserTest.php therefore ends up installed onto your computer as /usr/share/php/tests/CommandLineLib/Phix_Project/CommandLineLib/CommandLineParserTest.php.

There’s always the possibility that some Linux distros (and Mac OS X) will install doc files into a different folder. You can see where the PEAR installer will put these files on your computer by running:

$ sudo pear config-show | grep test_dir
PEAR test directory   test_dir          /usr/share/php/tests

What About Other Kinds Of Test Code?

In the PHP component skeleton, the src/tests/functional-tests folder is available for anyone who wants to add any automated testing to prove that their app works. Selenium is a tool that might help with this.

There’s also the src/tests/integration-tests folder available for anyone who wants to maintain a strict separation between unit tests (which, technically, should prove that a single class works as required) and integration tests (which, technically, should prove that a collection of classes work together as required, especially across system boundaries).

At the time of writing, the component skeleton doesn’t do anything with code inside these folders. Patches are most welcome!

5 Comments

  1. Christian Weiske says:
    August 15th, 2011 at 8:34 am

    You can run the unit tests from the package via PEAR, too:

    $ pear run-tests -up package_name

    (requires a AllTests.php file, though)

  2. Daniel O'Connor says:
    August 15th, 2011 at 11:59 pm

    One of the things many authors within PEAR aren’t 100% clear on is where tests should be runnable from. The defacto feeling within PEAR is that your package should not need to be installed to enable tests.

    I tend towards saying tests should always be executed from the top level src directory.

    Say you have a component living in My/Component.php

    $ cd My_Component/trunk/src/
    $ phpunit tests/

    Your test would simply require_once “My/Component.php”; and execute happily. When installed by the PEAR installer, it would locate My/Component.php in the include path and also execute.

    This avoids any need to do:
    require_once dirname(__FILE__) . /path/to/my/trunk/src/My/Component.php
    … and ensures that when you are in the top level directory; your tests are running on your local svn version (not a different, installed version).

    The one problem I see and don’t tend to have a great answer for is components with dependencies – the installer solves this problem; but there are few reliable ways to check that all dependencies are available and installed when running your tests from version control directly.
    Mechanisms like svn:externals can go some way towards fixing this; or pre-installing your dependencies; but neither is a clean solution.

  3. Stuart Herbert says:
    August 16th, 2011 at 4:04 pm

    @Christian thanks. That doesn’t seem to be documented anywhere in PEAR’s documentation?

  4. Hari K T says:
    August 16th, 2011 at 4:33 pm

    I feel the structure is mainly because the pear keeps the packages there.

    The one thing I loved in Aura is we have the phpunit coming inside the system where we can write tests and run tests for the components. We don’t need to go and install phpunit and all those stuffs. Also we don’t want pear :) . Just download and put in the package folder. The system acts as a full stack framework also.

    For more information

    http://auraphp.github.com/

    http://auraphp.github.com/system/

  5. Stuart Herbert says:
    August 16th, 2011 at 9:32 pm

    I deliberately chose to base this work on compatibility with the PEAR installer, for all its faults, because interoperability is very important if we’re going to create a PHP components eco-system. ‘Just download’ suggests little-to-no dependency management, which might be fine in a single-stack framework, but isn’t really the way that other component ecosystems (such as CPAN and Gems) have gone.