Funcții care aruncă excepții
Multe funcții PHP refuză datele de intrare greșite aruncând o excepție: în caz de succes returnează rezultatul, iar în caz de eșec aruncă o excepție și nu returnează nimic.
Un test pentru o astfel de funcție trebuie să verifice ambele căi: intrarea bună returnează valoarea corectă fără a arunca excepție, iar intrarea greșită aruncă efectiv o excepție — o funcție care acceptă în silență date greșite este și ea o eroare.
Calea bună
Pentru o intrare validă, testul doar apelează funcția și compară valoarea. Nu este nevoie de nicio verificare suplimentară a erorii: dacă apelul aruncă o excepție neașteptată, PHPUnit raportează excepția și face testul să eșueze de la sine.
Intrare validă, fără excepție
safeDivide(10, 2) trebuie să returneze 5.0 și să nu arunce nimic. Un singur assertSame acoperă totul — o excepție neașteptată ar face testul să eșueze fără cod suplimentar.
Ieșire: script PHP
<?php
use PHPUnit\Framework\TestCase;
function safeDivide(float $a, float $b): float {
if ($b == 0) {
throw new InvalidArgumentException("nu se poate împărți la zero");
}
return $a / $b;
}
final class SafeDivideTest extends TestCase {
public function testSafeDivideGood(): void {
$this->assertSame(5.0, safeDivide(10, 2));
}
}
Calea greșită
Cealaltă jumătate a contractului: datele de intrare greșite trebuie să arunce o excepție. Testul declară așteptarea înainte de apel, cu expectException, apoi apelează funcția.
Dacă apelul aruncă excepția declarată, așteptarea contează ca o verificare trecută. Dacă apelul returnează normal, testul eșuează — funcția a acceptat date pe care ar fi trebuit să le respingă.
Intrarea greșită trebuie să arunce o excepție
Împărțirea la zero trebuie să eșueze. Testul așteaptă o InvalidArgumentException; safeDivide(10, 0) o aruncă, așa că rularea raportează OK (1 test, 1 assertion). Un safeDivide care ar returna aici o valoare ar face testul să eșueze.
Ieșire: script PHP
<?php
use PHPUnit\Framework\TestCase;
function safeDivide(float $a, float $b): float {
if ($b == 0) {
throw new InvalidArgumentException("nu se poate împărți la zero");
}
return $a / $b;
}
final class SafeDivideTest extends TestCase {
public function testSafeDivideByZero(): void {
$this->expectException(InvalidArgumentException::class);
safeDivide(10, 0);
}
}
Un tabel cu throws
Ambele căi încap într-un singur data provider: dă fiecărui rând un câmp throws care spune dacă se așteaptă o excepție.
Metoda de test verifică mai întâi acel câmp — pentru un rând care aruncă excepție declară expectException, apelează funcția și iese. Pentru rândurile bune compară valoarea ca de obicei.
Cazuri bune și greșite într-un singur tabel
Patru rânduri: trei împărțiri normale și o împărțire la zero, cu throws setat pe true. O singură metodă de test acoperă tot contractul funcției — rulată cu --testdox, toate cele patru cazuri trec.
Ieșire: script PHP
<?php
use PHPUnit\Framework\TestCase;
use PHPUnit\Framework\Attributes\DataProvider;
function safeDivide(float $a, float $b): float {
if ($b == 0) {
throw new InvalidArgumentException("nu se poate împărți la zero");
}
return $a / $b;
}
final class SafeDivideTest extends TestCase {
public static function divideCases(): array {
return [
"simple division" => [10, 2, 5.0, false],
"negative result" => [-9, 3, -3.0, false],
"divide zero" => [0, 5, 0.0, false],
"divide by zero" => [10, 0, 0.0, true],
];
}
#[DataProvider('divideCases')]
public function testSafeDivide(float $a, float $b, float $want, bool $throws): void {
if ($throws) {
$this->expectException(InvalidArgumentException::class);
safeDivide($a, $b);
return;
}
$this->assertSame($want, safeDivide($a, $b));
}
}