Debugging starts by reproducing one failure with known input and an observable result. Testing records the behavior that should remain true after the repair.
Prefer small pure functions and explicit dependencies because they can be exercised without a browser, database, or global state.
<?php
declare(strict_types=1);
function discountedTotal(float $total, int $percent): float
{
if ($percent < 0 || $percent > 100) {
throw new InvalidArgumentException('Invalid discount.');
}
return $total * (1 - $percent / 100);
}
A PHPUnit test class extends TestCase. A test arranges input, performs one action, and asserts the observable result. Install the PHPUnit version compatible with the project runtime through Composer.
<?php
declare(strict_types=1);
use PHPUnit\Framework\TestCase;
final class DiscountTest extends TestCase
{
public function testAppliesDiscount(): void
{
self::assertSame(80.0, discountedTotal(100.0, 20));
}
public function testRejectsInvalidPercentage(): void
{
$this->expectException(InvalidArgumentException::class);
discountedTotal(100.0, 120);
}
}
Choose the smallest test boundary that can prove the risk. Unit tests exercise a decision without external services, integration tests prove adapters such as PDO against the real boundary, and a small number of end-to-end tests confirm that routing, sessions, templates, and infrastructure cooperate.
| Test | Best Evidence | Typical Cost |
|---|---|---|
| Unit | Domain calculation or policy | Fast and isolated |
| Integration | SQL mapping, filesystem, HTTP adapter | Boundary setup and cleanup |
| End to end | Critical user workflow | Slowest and broadest diagnosis |
Use a fake when a lightweight working implementation makes the test clear, a stub when the test needs a controlled answer, and a mock when the interaction itself is the behavior being verified. Prefer asserting the returned state or result over a long sequence of internal calls.
<?php
final class InMemoryTaskRepository implements TaskRepository
{
/** @var list<string> */
public array $titles = [];
public function save(string $title): int
{
$this->titles[] = $title;
return count($this->titles);
}
}
The fake supports application tests without replacing the separate PDO integration tests that verify SQL behavior.
| Command | Purpose |
|---|---|
| php -l src/File.php | Check syntax without execution |
| php script.php | Run a focused CLI reproduction |
| composer test | Run the project-defined test script |
| vendor/bin/phpunit | Run PHPUnit directly when installed |
0 of 2 checked
Try this next
0 of 2 completed
Explore 500+ free tutorials across 20+ languages and frameworks.