TestDox
TestDox is a feature that allows tests to serve not only as executable verification but also as executable specification and executable documentation.
During test-driven development (TDD), tests are written before the production code. In this context, the tests serve as an executable specification: they describe the expected behaviour of the code that is yet to be written. Once the production code has been written, the tests continue to serve as executable documentation: they describe the actual behaviour of the code.
TestDox renders test method names as human-readable sentences. When used together with the --testdox CLI option, it provides a behaviour-driven view of your test suite that reads like documentation.
Default Behaviour
By default, PHPUnit uses the naming conventions of test classes and test methods to generate human-readable documentation.
Class Names
A test class name is prettified by removing the Test suffix, then splitting the camelCase name into words. For example, GreeterTest becomes Greeter.
When the test class is in a namespace, the unqualified class name is used as the title with the fully qualified class name (without the Test suffix) in parentheses. For example, App\Tests\GreeterTest becomes Greeter (App\Tests\Greeter).
Method Names
A test method name is prettified by removing the test prefix (or test_ for snake_case method names), then converting the remainder to a sentence:
camelCase:
testGreetsWithNamebecomesGreets with namesnake_case:
test_greets_with_namebecomesGreets with nameNumbers:
testValueIsGreaterThan0becomesValue is greater than 0
Consider the following test class:
<?php declare(strict_types=1);
final class Greeter
{
public function greet(string $name): string
{
return 'Hello, ' . $name . '!';
}
public function greetWithTimeOfDay(string $name, int $hour): string
{
if ($hour < 12) {
return 'Good morning, ' . $name . '!';
}
if ($hour < 18) {
return 'Good afternoon, ' . $name . '!';
}
return 'Good evening, ' . $name . '!';
}
}
<?php declare(strict_types=1);
use PHPUnit\Framework\TestCase;
final class GreeterTest extends TestCase
{
public function testGreetsWithName(): void
{
$greeter = new Greeter;
$this->assertSame('Hello, World!', $greeter->greet('World'));
}
public function testGreetsWithGoodMorningBeforeNoon(): void
{
$greeter = new Greeter;
$this->assertSame(
'Good morning, Alice!',
$greeter->greetWithTimeOfDay('Alice', 9),
);
}
public function testGreetsWithGoodAfternoonAfterNoon(): void
{
$greeter = new Greeter;
$this->assertSame(
'Good afternoon, Alice!',
$greeter->greetWithTimeOfDay('Alice', 14),
);
}
public function testGreetsWithGoodEveningAfter6Pm(): void
{
$greeter = new Greeter;
$this->assertSame(
'Good evening, Alice!',
$greeter->greetWithTimeOfDay('Alice', 20),
);
}
}
Running this test with the --testdox option yields the output shown below:
$ ./tools/phpunit --no-progress --testdox tests/GreeterTest.php PHPUnit 13.2.0 by Sebastian Bergmann and contributors. Runtime: PHP 8.5.3 Time: 00:00.077, Memory: 10.00 MB Greeter ✔ Greets with name ✔ Greets with good morning before noon ✔ Greets with good afternoon after noon ✔ Greets with good evening after 6 pm OK (4 tests, 4 assertions)
Data Providers
When a test method uses a data provider, TestDox appends the data set information to the prettified method name:
For indexed data sets:
with data set #0For named data sets:
with "name"
Customizing Test Documentation
The default prettification is often sufficient, but there are cases where you want more control over the documentation text. PHPUnit provides three attributes for this purpose.
The TestDox Attribute
The TestDox(string $text) attribute can be used at the class level and/or the method level to specify custom documentation text.
At the class level, it replaces the prettified class name:
<?php declare(strict_types=1);
use PHPUnit\Framework\Attributes\TestDox;
use PHPUnit\Framework\TestCase;
#[TestDox('Greeting Service')]
final class GreeterTest extends TestCase
{
#[TestDox('Greets a person by their name')]
public function testGreetsWithName(): void
{
// ...
}
}
Running this test with TestDox output enabled yields:
Greeting Service
✔ Greets a person by their name
See TestDox for the attribute reference.
Using Placeholders with Data Providers
When the TestDox attribute is used on a test method that uses a data provider, you can embed placeholders that reference the method’s parameters. Each placeholder is the parameter name prefixed with $.
<?php declare(strict_types=1);
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\TestDox;
use PHPUnit\Framework\TestCase;
final class CalculatorTest extends TestCase
{
#[DataProvider('additionProvider')]
#[TestDox('Adding $a to $b results in $expected')]
public function testAdd(int $expected, int $a, int $b): void
{
$this->assertSame($expected, $a + $b);
}
public static function additionProvider(): array
{
return [
'zero plus zero' => [0, 0, 0],
'zero plus one' => [1, 0, 1],
'one plus zero' => [1, 1, 0],
'one plus one' => [2, 1, 1],
];
}
}
Running this test with TestDox output enabled yields:
Calculator
✔ Adding 0 to 0 results in 0
✔ Adding 0 to 1 results in 1
✔ Adding 1 to 0 results in 1
✔ Adding 1 to 1 results in 2
When placeholders are used, data provider information is not appended to the text because the parameter values are already embedded in the documentation text.
The special placeholder $_dataName is available and resolves to the name of the current data set (for example, zero plus zero or one plus one in the example shown above).
The TestDoxFormatter Attribute
The TestDoxFormatter(string $methodName) attribute can be used on a test method to specify a static method in the same class that formats the documentation text. This is useful when the documentation text requires logic that cannot be expressed with simple placeholders, for example when objects need to be formatted in a specific way.
The formatter method must be public and static. It receives the same parameters as the test method (from the data provider) and must return a string.
<?php declare(strict_types=1);
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\TestDoxFormatter;
use PHPUnit\Framework\TestCase;
final class ExampleTest extends TestCase
{
public static function provider(): array
{
return [
[
new DateTimeImmutable('2025-08-01'),
new DateTimeImmutable('2025-08-01'),
],
];
}
public static function formatter(DateTimeImmutable $expected, DateTimeImmutable $actual): string
{
return sprintf(
'%s is expected to be %s',
$actual->format('Y-m-d'),
$expected->format('Y-m-d'),
);
}
#[DataProvider('provider')]
#[TestDoxFormatter('formatter')]
public function testOne(DateTimeImmutable $expected, DateTimeImmutable $actual): void
{
$this->assertEquals($expected, $actual);
}
}
Running this test with TestDox output enabled yields:
Example
✔ 2025-08-01 is expected to be 2025-08-01
See TestDoxFormatter for the attribute reference.
The TestDoxFormatterExternal Attribute
The TestDoxFormatterExternal(string $className, string $methodName) attribute works like TestDoxFormatter, but references a public static method declared in another class. This is useful when multiple test classes share the same formatting logic.
See TestDoxFormatterExternal for the attribute reference.
TestDox Output
Console Output
The --testdox CLI option replaces the default result output with TestDox format. The following symbols are used to indicate the status of each test:
✔ Test passed
✘ Test failed or errored
↩ Test was skipped
⚠ Test triggered a warning
∅ Test is incomplete
The --testdox-summary CLI option repeats the TestDox output at the end of the test run for tests that had errors, failures, or issues. This provides a focused summary of problematic tests in TestDox format.
Plain Text Output
The --testdox-text <file> CLI option writes the test results in TestDox format as a plain text file. Successful tests are marked with [x] and defective tests are marked with [ ]:
Greeter
[x] Greets with name
[x] Greets with good morning before noon
[x] Greets with good afternoon after noon
[x] Greets with good evening after 6 pm
This can also be configured in the XML configuration file using the <testdoxText> element inside the <logging> element (see The <testdoxText> Element).
HTML Output
The --testdox-html <file> CLI option writes the test results in TestDox format as an HTML file. This produces a browsable document with styled results where successful tests are marked with a green ✓ and defective tests are marked with a red ✗.
This can also be configured in the XML configuration file using the <testdoxHtml> element inside the <logging> element (see The <testdoxHtml> Element).
XML Configuration
TestDox output can be enabled through the XML configuration file as an alternative to using CLI options.
The testdox attribute on the <phpunit> element enables TestDox console output (see The testdox Attribute).
The testdoxSummary attribute on the <phpunit> element enables the TestDox summary (see The testdoxSummary Attribute).
File-based TestDox output is configured using child elements of the <logging> element:
<phpunittestdox="true"testdoxSummary="true">
<logging>
<testdoxHtmloutputFile="testdox.html"/>
<testdoxTextoutputFile="testdox.txt"/>
</logging>
</phpunit>
© 2005–2026 Sebastian Bergmann
Licensed under the Creative Commons Attribution 3.0 Unported License.
https://docs.phpunit.de/en/13.2/testdox.html