What Is a Unit Test
A unit test is a small program that checks one piece of your code — usually one function. You run the tests after every change; if a change breaks something, a test tells you right away, before your users do.
The standard tool in the PHP world is PHPUnit. It is installed once per project with Composer — composer require --dev phpunit/phpunit — and the runner lands in the project at ./vendor/bin/phpunit.
Tests also make change safe: with good tests you can rewrite a function and know in seconds whether it still behaves the same.
Test Files, Classes and Methods
Three naming rules make a test a test:
1. The file name ends in Test.php — for calc.php you write CalcTest.php. PHPUnit looks for files named like that.
2. The class in the file extends TestCase, PHPUnit's base class, imported with use PHPUnit\Framework\TestCase;.
3. The method name starts with test — like testAdd. Methods without the prefix are not run as tests, so helpers can live in the same class.
Inside the test you call the function and hand the expected value and what you actually got to an assertion like $this->assertSame(5, add(2, 3)). A failed assertion marks the test as failed; no failure means the test passes.
A first passing test
testAdd calls add(2, 3) and compares the result with 5 in one assertSame. They match, so nothing fails and the run ends with OK (1 test, 1 assertion).
Output: PHP script
<?php
use PHPUnit\Framework\TestCase;
function add(int $a, int $b): int {
return $a + $b;
}
final class AddTest extends TestCase {
public function testAdd(): void {
$this->assertSame(5, add(2, 3));
}
}
A failing test
This add has a bug — it multiplies. The test catches it: PHPUnit names the test AddTest::testAdd, states the reason — Failed asserting that 6 is identical to 5. — with the file and line of the failed assertion, and the run ends with FAILURES!
Output: PHP script
<?php
use PHPUnit\Framework\TestCase;
// add has a bug: it multiplies instead of adding.
function add(int $a, int $b): int {
return $a * $b;
}
final class AddTest extends TestCase {
public function testAdd(): void {
$this->assertSame(5, add(2, 3));
}
}
Running Tests
./vendor/bin/phpunit AddTest.php runs every test in the file; called without a file name, PHPUnit runs the whole test suite of the project. The default output is short: one dot per passing test, an F per failure, and a summary line.
Add --testdox to list every test by name, each on its own line with a check mark under the class name. Use it to see what actually ran.
Two tests, listed by name
The file has two test methods, one per function under test. With --testdox, each shows up on its own line under the class name Calc — you can see both ran and both passed, and the summary says OK (2 tests, 2 assertions).
Output: PHP script
<?php
use PHPUnit\Framework\TestCase;
function double(int $n): int {
return $n * 2;
}
function half(int $n): int {
return intdiv($n, 2);
}
final class CalcTest extends TestCase {
public function testDouble(): void {
$this->assertSame(8, double(4));
}
public function testHalf(): void {
$this->assertSame(4, half(8));
}
}