How a Test Fails
Every check in a PHPUnit test is an assertion — assertSame, assertTrue, assertCount and many more. What happens after a failure decides how you structure a test:
A failed assertion stops its test method immediately — the lines after it never run. The other test methods of the class are unaffected: each runs and fails on its own.
That gives you two tools. Put independent checks into separate methods, so every broken one is reported. Put dependent checks in a row inside one method, so the test fails fast at the first broken step.
Report Everything: Separate Methods
When several cases should be checked in one run, give each its own test method. A broken case fails only its own method — the other methods still run, and every failure is listed.
That way one PHPUnit run shows you the whole damage — not just the first broken case.
See every broken case at once
This add ignores $b, so all three checks fail. Because each check is its own test method, all three failure messages appear in a single run — inside one method you would only see the first.
Output: PHP script
<?php
use PHPUnit\Framework\TestCase;
// add has a bug: it ignores $b.
function add(int $a, int $b): int {
return $a;
}
final class AddTest extends TestCase {
public function testAddTwoAndTwo(): void {
$this->assertSame(4, add(2, 2));
}
public function testAddTwoAndThree(): void {
$this->assertSame(5, add(2, 3));
}
public function testAddTenAndOne(): void {
$this->assertSame(11, add(10, 1));
}
}
Fail Fast: Assertions in a Row
Sometimes a failed check means the rest of the test cannot work. A typical case: the test first prepares a value, then inspects it. If the preparation already went wrong, inspecting would be useless or would even crash.
Assertions in a row inside one method do exactly that: the first failure stops the method right there. The checks after it never run — and that is the point.
Stop before the useless checks
splitWords has a bug (it splits on the wrong character), so 1 part comes back instead of 3. assertCount reports it and stops the method — the check of the first part below is never reached. The summary proves it: Assertions: 1, only one assertion ever ran.
Output: PHP script
<?php
use PHPUnit\Framework\TestCase;
// splitWords has a bug: it splits on ";" instead of ",".
function splitWords(string $s): array {
return explode(";", $s);
}
final class SplitTest extends TestCase {
public function testSplit(): void {
$parts = splitWords("one,two,three");
$this->assertCount(3, $parts);
// Never reached while the bug is there.
$this->assertSame("one", $parts[0]);
}
}
Messages on Assertions
Every assertion takes an optional last argument: a plain message that is printed only when the check fails. $this->assertTrue(isEven(4), "4 should be even") stays silent while the check passes and explains itself when it does not.
Plain messages
Two boolean checks with plain messages. Both pass here, so the messages stay silent and the run prints OK (1 test, 2 assertions).
Output: PHP script
<?php
use PHPUnit\Framework\TestCase;
function isEven(int $n): bool {
return $n % 2 === 0;
}
final class IsEvenTest extends TestCase {
public function testIsEven(): void {
$this->assertTrue(isEven(4), "4 should be even");
$this->assertFalse(isEven(3), "3 should not be even");
}
}