Chapter 3. Installing PHPUnit

Requirements

PHPUnit 3.7 requires PHP 5.3.3; using the latest version of PHP is highly recommended.

PHPUnit requires the ctype, dom, json, pcre, reflection, and spl extensions. These extensions are usually compiled and enabled by default. Some of them cannot even be disabled and are therefore always available.

For code coverage support, Xdebug 2.1.3 is required; using the latest version of Xdebug is highly recommended. The tokenizer extension is also required for the code coverage functionality to work.

The phar extension is required for using PHPUnit from a PHP Archive (PHAR). You need to configure suhosin.executor.include.whitelist = phar if you are using the Suhosin extension and would like to use PHPUnit from a PHP Archive (PHAR).

PHP Archive (PHAR)

The easiest way to obtain PHPUnit is to download a PHP Archive (PHAR) that has all required (as well as some optional) dependencies of PHPUnit bundled in a single file:

wget https://phar.phpunit.de/phpunit.phar
chmod +x phpunit.phar
mv phpunit.phar /usr/local/bin/phpunit

You can also immediately use the PHAR after you have downloaded it, of course:

wget https://phar.phpunit.de/phpunit.phar
php phpunit.phar

Verifying PHPUnit PHAR Releases

All official releases of code distributed by the PHPUnit Project are signed by the release manager for the release. PGP signatures and SHA1 hashes are available for verification on phar.phpunit.de.

The following example details how release verification works. We start by downloading phpunit.phar as well as its detached PGP signature phpunit.phar.asc:

wget https://phar.phpunit.de/phpunit.phar
wget https://phar.phpunit.de/phpunit.phar.asc

We want to verify PHPUnit's PHP Archive (phpunit.phar) against its detached signature (phpunit.phar.asc):

gpg phpunit.phar.asc
gpg: Signature made Sat 19 Jul 2014 01:28:02 PM CEST using RSA key ID 6372C20A
gpg: Can't check signature: public key not found

We don't have the release manager's public key (6372C20A) in our local system. In order to proceed with the verification we need to retrieve the release manager's public key from a key server. One such server is pgp.uni-mainz.de. The public key servers are linked together, so you should be able to connect to any key server.

gpg --keyserver pgp.uni-mainz.de --recv-keys 0x4AA394086372C20A
gpg: requesting key 6372C20A from hkp server pgp.uni-mainz.de
gpg: key 6372C20A: public key "Sebastian Bergmann <sb@sebastian-bergmann.de>" imported
gpg: Total number processed: 1
gpg:               imported: 1  (RSA: 1)

Now we have received a public key for an entity known as "Sebastian Bergmann <sb@sebastian-bergmann.de>". However, we have no way of verifying this key was created by the person known as Sebastian Bergmann. But, let's try to verify the release signature again.

gpg phpunit.phar.asc
gpg: Signature made Sat 19 Jul 2014 01:28:02 PM CEST using RSA key ID 6372C20A
gpg: Good signature from "Sebastian Bergmann <sb@sebastian-bergmann.de>"
gpg:                 aka "Sebastian Bergmann <sebastian@php.net>"
gpg:                 aka "Sebastian Bergmann <sebastian@thephp.cc>"
gpg:                 aka "Sebastian Bergmann <sebastian@phpunit.de>"
gpg:                 aka "Sebastian Bergmann <sebastian.bergmann@thephp.cc>"
gpg:                 aka "[jpeg image of size 40635]"
gpg: WARNING: This key is not certified with a trusted signature!
gpg:          There is no indication that the signature belongs to the owner.
Primary key fingerprint: D840 6D0D 8294 7747 2937  7831 4AA3 9408 6372 C20A

At this point, the signature is good, but we don't trust this key. A good signature means that the file has not been tampered. However, due to the nature of public key cryptography, you need to additionally verify that key 6372C20A was created by the real Sebastian Bergmann.

Any attacker can create a public key and upload it to the public key servers. They can then create a malicious release signed by this fake key. Then, if you tried to verify the signature of this corrupt release, it would succeed because the key was not the "real" key. Therefore, you need to validate the authenticity of this key. Validating the authenticity of a public key, however, is outside the scope of this documentation.

Composer

Simply add a dependency on phpunit/phpunit to your project's composer.json file if you use Composer to manage the dependencies of your project. Here is a minimal example of a composer.json file that just defines a development-time dependency on PHPUnit 3.7:

{
    "require-dev": {
        "phpunit/phpunit": "3.7.*"
    }
}

For a system-wide installation via Composer, you can run:

composer global require "phpunit/phpunit=3.7.*"

Make sure you have ~/.composer/vendor/bin/ in your path.

Note

Support for Composer and PHP Archive (PHAR) was added in PHPUnit 3.7 (and is known to be stable since PHPUnit 3.7.5). Earlier releases of PHPUnit are not available through these distribution channels.

Optional packages

The following optional packages are available:

PHP_Invoker

A utility class for invoking callables with a timeout. This package is required to enforce test timeouts in strict mode.

This package is included in the PHAR distribution of PHPUnit. It can be installed via Composer by adding the following "require-dev" dependency:

"phpunit/php-invoker": "*"
DbUnit

DbUnit port for PHP/PHPUnit to support database interaction testing.

This package is included in the PHAR distribution of PHPUnit. It can be installed via Composer by adding the following "require-dev" dependency:

"phpunit/dbunit": ">=1.2"
PHPUnit_Selenium

Selenium RC integration for PHPUnit.

This package is included in the PHAR distribution of PHPUnit. It can be installed via Composer by adding the following "require-dev" dependency:

"phpunit/phpunit-selenium": ">=1.2"

Upgrading

This section serves as a collection of minor BC issues that one might run into when upgrading from PHPUnit 3.6 to PHPUnit 3.7.

The upgrade should be rather easy and work without any issues as it was tested against all major Open Source frameworks and there was not a single problem for them. Still every project is different and if you did not get around to trying one of the release candidates and have ran into an issue this document might provide some help.

Removed deprecated OutputTestCase

The class PHPUnit_Extensions_OutputTestCase has been removed. PHPUnit 3.6 issued a deprecation notice when it was used. To see how output can now be tested look into the section called “Testing Output”.

Current working directory will be restored after each test case

If a test changes the current working directory (cwd) PHPUnit ran into issues when generating code coverage output. Now that the cwd is restored after each test case you might find that one of your tests depended on another test changing the cwd. Something that isn't desirable anyways and should be easy to fix.

Test listeners trigger one autoload call

When using custom test listeners as described in the section called “Test Listeners” PHPUnit silently ignored missing test listeners and it was quite hard to debug that issues for the user. Now one autoload call will be triggered trying to locate the class. If your autoloader produces an error when it doesn't find a test listener you might run into an issue here. Removing the listener or making sure it's loaded in your bootstrap.php will solve this.

Parameters for mock objects do not get cloned anymore

Previously all object parameters where cloned when mocking. This lead to issues when testing trying to check whether the same object was passed to method or not and other problem with uncloneable objects. As a long standing feature request by many this behavior was changed. Example 10.15 shows where the new implementation could be useful. Example 10.16 shows how to switch back to previous behavior.

addUncoveredFilesFromWhitelist was removed in favor of processUncoveredFilesFromWhitelist

When generating code coverage and using <whitelist addUncoveredFilesFromWhitelist="true"> all uncovered files got included by PHPUnit. This was an issue for people with executable code in those files. PHPUnit will now scan the file and guess what code is executable and what code is not without including it. This might lead to different code coverage reports.

To switch back to the old behavior the setting <whitelist processUncoveredFilesFromWhitelist="true"> can be used. If you want the behavior with PHPUnit 3.6. and 3.7. it is possible to use both settings for a while.

Default value of cacheTokens changed to false

Since PHPUnit 3.7.2 we turned off the caching of tokenized files by default. When processing code coverage reports for big projects this cache consumed a lot of memory and due to the change in whitelist behavior it was problematic for folks with code bases with more than a couple of thousand classes.

If your project is smaller or you have enough memory you will get a runtime benefit by adding cacheTokens="true" to your phpunit.xml file. See the section called “PHPUnit”.