testing php applications
Pest Datasets
Pest datasets run one test shape against several examples. They are the Pest equivalent of table-driven checks and work well for validation rules, calculations, and boundary conditions.
Name Boundary Cases
A dataset should expose the meaning of each row. Thresholds, empty values, malformed values, and representative normal values deserve names that make a failure understandable.
Share Only Stable Data
Datasets can be local to a file or shared more broadly. Keep shared datasets purposeful; a giant global bag of fixtures makes ownership unclear.
PHP example
<?php
declare(strict_types=1);
function discount(int $totalPence): int
{
return $totalPence >= 10_000 ? intdiv($totalPence, 10) : 0;
}
test('calculates discount', function (int $totalPence, int $expected): void {
expect(discount($totalPence))->toBe($expected);
})->with([
'below threshold' => [9_999, 0],
'at threshold' => [10_000, 1_000],
'above threshold' => [15_000, 1_500],
]);
Common Mistakes
- Unnamed values that make failures cryptic.
- Mixing unrelated behaviours.
- Sharing datasets globally without a real reuse need.
- Using large datasets instead of targeted examples.
What To Practise
- Build named Pest datasets.
- Cover rule boundaries.
- Keep shared test data understandable.
Practice
Practice: Create A Password-Length Dataset
Define named examples for a registration rule requiring at least 12 characters.
Requirements
- Include empty, 11-character, 12-character, and longer examples.
- Name each case.
- Store input and expected acceptance together.
- Keep the dataset focused on length only.
Show solution
The dataset identifies the exact boundary.
PHP example
<?php
declare(strict_types=1);
$passwords = [
'empty' => ['', false],
'eleven characters' => ['abcdefghijk', false],
'twelve characters' => ['abcdefghijkl', true],
'longer password' => ['correct horse battery staple', true],
];
foreach ($passwords as $name => [$password, $accepted]) {
echo $name . ': ' . ($accepted ? 'accepted' : 'rejected') . PHP_EOL;
}
// Prints:
// empty: rejected
// eleven characters: rejected
// twelve characters: accepted
// longer password: accepted
A Pest test can receive each dataset row and apply one expectation to the validation rule.