DocTestTest Your Documentation
Extract PHP code blocks from markdown. Execute them. Verify the output. Automatically.
Extract PHP code blocks from markdown. Execute them. Verify the output. Automatically.
Add an assertion after any PHP code block in your markdown. DocTest extracts the code, runs it, and verifies the output matches.
Your rendered documentation stays clean — assertions live in HTML comments, invisible to readers.
```php
echo 'Hello, World!';
```
<!-- doctest: Hello, World! -->vendor/bin/doctest
README.md
:3 ✔ echo 'Hello, World!'; [1/1] 0.02s
----------------------------------------
Blocks: 1 Passed: 1 Duration: 0.05sFrom exact output matching to JSON comparison, DocTest gives you the right tool for every situation.
HTML comments keep assertions invisible to readers. Use // => for inline result checks.
```php
echo 'Hello';
```
<!-- doctest: Hello -->
```php
echo 'The quick brown fox';
```
<!-- doctest-contains: brown fox -->
```php
echo date('Y');
```
<!-- doctest-matches: /^\d{4}$/ -->
```php
echo json_encode(['status' => 'ok']);
```
<!-- doctest-json: {"status": "ok"} -->
```php
$sum = array_sum([1, 2, 3]);
```
<!-- doctest-expect: $sum === 6 -->
```php
$x = 42; // => 42
```Skip blocks, expect exceptions, or check syntax only. Attributes on the code fence give you precise control over how each block is handled.
```php ignore
// This block won't be executed
$config = require 'missing-file.php';
```
```php throws(InvalidArgumentException)
throw new InvalidArgumentException('Bad input');
```
```php no_run
// Syntax checked, not executed
$db->query('SELECT * FROM users');
```When output contains timestamps, IDs, or other dynamic values, wildcards let you match the pattern without hardcoding the value.
```php
echo 'Request took 42ms at ' . date('Y-m-d');
```
<!-- doctest: Request took {{int}}ms at {{date}} -->
```php
echo json_encode([
'id' => '550e8400-e29b-41d4-a716-446655440000',
'time' => '14:30:00',
'cost' => 19.99,
]);
```
<!-- doctest: {"id":"{{uuid}}","time":"{{time}}","cost":{{float}}} -->Group related code blocks to share variables across examples. Add setup and teardown blocks for database connections or other resources.
```php setup group="database"
$pdo = new PDO('sqlite::memory:');
$pdo->exec('CREATE TABLE users (
id INTEGER PRIMARY KEY,
name TEXT
)');
```
```php group="database"
$pdo->exec("INSERT INTO users (name) VALUES ('Alice')");
$count = $pdo->query('SELECT COUNT(*) FROM users')
->fetchColumn();
echo $count;
```
<!-- doctest: 1 -->
```php teardown group="database"
$pdo->exec('DROP TABLE users');
```Add one line to your CI pipeline. DocTest returns proper exit codes and generates JUnit XML reports for your CI dashboard.
# .github/workflows/docs.yml
name: Documentation Tests
on: [push, pull_request]
jobs:
doctest:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: shivammathur/setup-php@v2
with:
php-version: '8.4'
- run: composer install
- run: vendor/bin/doctest