4. Organizing Tests

One of the goals of PHPUnit is that tests should be composable: we want to be able to run any number or combination of tests together, for instance all tests for the whole project, or the tests for all classes of a component that is part of the project, or just the tests for a single class.

PHPUnit supports different ways of organizing tests and composing them into a test suite. This chapter shows the most commonly used approaches.

Composing a Test Suite Using the Filesystem

Probably the easiest way to compose a test suite is to keep all test case source files in a test directory. PHPUnit can automatically discover and run the tests by recursively traversing the test directory.

Lets take a look at the test suite of the sebastianbergmann/raytracer project.

Looking at this project’s directory structure, we see that the test case classes in the tests/unit directory mirror the package and class structure of the System Under Test (SUT) in the src directory:

  1. src tests/unit
  2. ├── autoload.php ├── CameraTest.php
  3. ├── Camera.php ├── canvas
  4. ├── canvas ├── AnsiMapperTest.php
  5. ├── AnsiMapper.php ├── CanvasTest.php
  6. ├── CanvasIterator.php └── PortablePixmapMapperTest.php
  7. ├── Canvas.php ├── ColorTest.php
  8. ├── PortablePixmapMapper.php ├── intersection
  9. └── WebpMapper.php ├── IntersectionCollectionTest.php
  10. ├── Color.php └── IntersectionTest.php
  11. ├── exceptions ├── material
  12. ├── Exception.php ├── CheckersPatternTest.php
  13. ├── IntersectionHasNoHitException.php ├── GradientPatternTest.php
  14. ├── InvalidArgumentException.php ├── MaterialTest.php
  15. ├── OutOfBoundsException.php ├── PatternTest.php
  16. ├── RuntimeException.php ├── RingPatternTest.php
  17. └── WorldHasNoLightException.php └── StripePatternTest.php
  18. ├── intersection ├── math
  19. ├── IntersectionCollectionIterator.php ├── MatrixTest.php
  20. ├── IntersectionCollection.php ├── RayTest.php
  21. ├── Intersection.php ├── TransformationsTest.php
  22. └── PreparedComputation.php └── TupleTest.php
  23. ├── material ├── PointLightTest.php
  24. ├── CheckersPattern.php ├── shapes
  25. ├── GradientPattern.php ├── PlaneTest.php
  26. ├── Material.php ├── ShapeCollectionTest.php
  27. ├── Pattern.php ├── ShapeTest.php
  28. ├── RingPattern.php └── SphereTest.php
  29. └── StripePattern.php └── WorldTest.php
  30. ├── math
  31. ├── Matrix.php tests/integration
  32. ├── Ray.php └── PuttingItTogetherTest.php
  33. ├── Transformations.php
  34. └── Tuple.php
  35. ├── PointLight.php
  36. ├── shapes
  37. ├── Plane.php
  38. ├── ShapeCollectionIterator.php
  39. ├── ShapeCollection.php
  40. ├── Shape.php
  41. └── Sphere.php
  42. └── World.php

The tests/integration directory contains integration test cases that are kept separate from the tests/unit directory’s unit tests.

To run all tests for this project can need to point the PHPUnit command-line test runner to the test directory:

  1. $ ./tools/phpunit --bootstrap tests/bootstrap.php tests
  2. PHPUnit 10.0.0 by Sebastian Bergmann and contributors.
  3. Runtime: PHP 8.2.2
  4. ............................................................... 63 / 177 ( 35%)
  5. ............................................................... 126 / 177 ( 71%)
  6. ................................................... 177 / 177 (100%)
  7. Time: 00:17.100, Memory: 28.27 MB
  8. OK (177 tests, 657 assertions)

Note

If you point the PHPUnit command-line test runner to a directory it will look for *Test.php files.

To run only the tests that are declared in the WorldTest test case class in tests/unit/WorldTest.php we can use the following command:

  1. $ ./tools/phpunit --bootstrap src/autoload.php tests/unit/WorldTest.php
  2. PHPUnit 10.0.0 by Sebastian Bergmann and contributors.
  3. Runtime: PHP 8.2.2
  4. ............. 13 / 13 (100%)
  5. Time: 00:00.095, Memory: 8.00 MB
  6. OK (13 tests, 30 assertions)

For more fine-grained control of which tests to run we can use the --filter option:

  1. $ ./tools/phpunit --bootstrap src/autoload.php tests/unit --filter test_creating_a_world
  2. PHPUnit 10.0.0 by Sebastian Bergmann and contributors.
  3. Runtime: PHP 8.2.2
  4. . 1 / 1 (100%)
  5. Time: 00:00.077, Memory: 10.00 MB
  6. OK (1 test, 2 assertions)

Composing a Test Suite Using XML Configuration

PHPUnit’s XML configuration file (The XML Configuration File) can also be used to compose a test suite. Example 4.1 shows a minimal phpunit.xml file that will add all *Test classes that are found in *Test.php files when the tests directory is recursively traversed.

Example 4.1 Composing a Test Suite Using XML Configuration

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3. xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/|version|/phpunit.xsd"
  4. bootstrap="tests/bootstrap.php">
  5. <testsuites>
  6. <testsuite name="unit">
  7. <directory>tests/unit</directory>
  8. </testsuite>
  9. <testsuite name="integration">
  10. <directory>tests/integration</directory>
  11. </testsuite>
  12. </testsuites>
  13. </phpunit>

Now that we have an XML configuration file, we can invoke the PHPUnit test runner without arguments (tests, for instance) or options (--bootstrap, for instance) to run our tests:

  1. $ ./tools/phpunit
  2. PHPUnit 10.0.0 by Sebastian Bergmann and contributors.
  3. Runtime: PHP 8.2.2
  4. Configuration: /path/to/raytracer/phpunit.xml
  5. ............................................................... 63 / 177 ( 35%)
  6. ............................................................... 126 / 177 ( 71%)
  7. ................................................... 177 / 177 (100%)
  8. Time: 00:17.100, Memory: 28.27 MB
  9. OK (177 tests, 657 assertions)

The PHPUnit test runner’s --list-suites option can be used to print a list of all test suites defined in PHPUnit’s XML configuration file:

  1. $ ./tools/phpunit --list-suites
  2. PHPUnit 10.0.0 by Sebastian Bergmann and contributors.
  3. Available test suite(s):
  4. - unit
  5. - integration

We can use the PHPUnit test runner’s --testsuite option to limit the tests that are run to the tests of a specific test suite that is declared in the XML configuration file:

  1. $ ./tools/phpunit --testsuite unit
  2. PHPUnit 10.0.0 by Sebastian Bergmann and contributors.
  3. Runtime: PHP 8.2.2
  4. Configuration: /path/to/raytracer/phpunit.xml
  5. ............................................................... 63 / 172 ( 36%)
  6. ............................................................... 126 / 172 ( 73%)
  7. .............................................. 172 / 172 (100%)
  8. Time: 00:00.213, Memory: 24.27 MB
  9. OK (172 tests, 637 assertions)