Assertok
Az assertok arra szolgálnak, hogy megerősítsék, hogy a tényleges érték megfelel a várt értéknek. Ezek a
Tester\Assert
osztály metódusai.
Válassza ki a legmegfelelőbb assertokat. Jobb az Assert::same($a, $b)
, mint az
Assert::true($a === $b)
, mert hiba esetén értelmes hibaüzenetet jelenít meg. A második esetben csak
false should be true
, ami semmit sem mond nekünk az $a
és $b
változók
tartalmáról.
A legtöbb assertnak lehet egy opcionális leírása is a $description
paraméterben, amely a hibaüzenetben
jelenik meg, ha az elvárás meghiúsul.
A példák feltételezik egy alias létrehozását:
use Tester\Assert;
Assert::same ($expected, $actual, ?string $description=null)
Az $expected
-nek azonosnak kell lennie az $actual
-lal. Ugyanaz, mint a PHP ===
operátora.
Assert::notSame ($expected, $actual, ?string $description=null)
Az Assert::same()
ellentéte, tehát ugyanaz, mint a PHP !==
operátora.
Assert::equal ($expected, $actual, ?string $description=null, bool $matchOrder=false, bool $matchIdentity=false)
Az $expected
-nek egyenlőnek kell lennie az $actual
-lal. Az Assert::same()
-től
eltérően figyelmen kívül hagyja az objektumok identitását, a kulcs ⇒ érték párok sorrendjét a tömbökben és a
marginálisan eltérő tizedes számokat, amit a $matchIdentity
és $matchOrder
beállításával lehet
megváltoztatni.
A következő esetek az equal()
szempontjából megegyeznek, de a same()
szempontjából nem:
Assert::equal(0.3, 0.1 + 0.2);
Assert::equal($obj, clone $obj);
Assert::equal(
['first' => 11, 'second' => 22],
['second' => 22, 'first' => 11],
);
Azonban vigyázat, az [1, 2]
és [2, 1]
tömbök nem egyenlőek, mert csak az értékek sorrendje
különbözik, nem a kulcs ⇒ érték pároké. Az [1, 2]
tömböt [0 => 1, 1 => 2]
-ként is fel
lehet írni, ezért az [1 => 2, 0 => 1]
fog egyenlőnek számítani.
Továbbá az $expected
-ben használhatók az ún. elvárások.
Assert::notEqual ($expected, $actual, ?string $description=null)
Az Assert::equal()
ellentéte.
Assert::contains ($needle, string|array $actual, ?string $description=null)
Ha az $actual
egy string, tartalmaznia kell a $needle
részstringet. Ha tömb, tartalmaznia kell a
$needle
elemet (szigorúan hasonlítva).
Assert::notContains ($needle, string|array $actual, ?string $description=null)
Az Assert::contains()
ellentéte.
Assert::hasKey (string|int $needle, array $actual, ?string $description=null)
Az $actual
-nak tömbnek kell lennie, és tartalmaznia kell a $needle
kulcsot.
Assert::notHasKey (string|int $needle, array $actual, ?string $description=null)
Az $actual
-nak tömbnek kell lennie, és nem tartalmazhatja a $needle
kulcsot.
Assert::true ($value, ?string $description=null)
Az $value
-nak true
-nak kell lennie, tehát $value === true
.
Assert::truthy ($value, ?string $description=null)
Az $value
-nak igaznak kell lennie (truthy), tehát teljesíti az if ($value) ...
feltételt.
Assert::false ($value, ?string $description=null)
Az $value
-nak false
-nak kell lennie, tehát $value === false
.
Assert::falsey ($value, ?string $description=null)
Az $value
-nak hamisnak kell lennie (falsey), tehát teljesíti az if (!$value) ...
feltételt.
Assert::null ($value, ?string $description=null)
Az $value
-nak null
-nak kell lennie, tehát $value === null
.
Assert::notNull ($value, ?string $description=null)
Az $value
-nak nem szabad null
-nak lennie, tehát $value !== null
.
Assert::nan ($value, ?string $description=null)
Az $value
-nak Not a Number-nek kell lennie. NAN értékek tesztelésére kizárólag az
Assert::nan()
-t használja. A NAN érték nagyon specifikus, és az Assert::same()
vagy
Assert::equal()
asszerciók váratlanul működhetnek.
Assert::count ($count, Countable|array $value, ?string $description=null)
Az elemek száma az $value
-ban $count
kell, hogy legyen. Tehát ugyanaz, mint
count($value) === $count
.
Assert::type (string|object $type, $value, ?string $description=null)
Az $value
-nak adott típusúnak kell lennie. $type
-ként használhatunk stringet:
array
list
– nullától kezdődő, növekvő sorrendű numerikus kulcsokkal indexelt tömbbool
callable
float
int
null
object
resource
scalar
string
- osztálynév vagy közvetlenül objektum, ekkor az
$value instanceof $type
kell, hogy legyen
Assert::exception (callable $callable, string $class, ?string $message=null, $code=null)
A $callable
hívásakor a $class
osztályú kivételnek kell dobódnia. Ha megadjuk a
$message
-t, a kivétel üzenetének is meg kell felelnie a mintának, és ha megadjuk
a $code
-ot, a kódoknak is szigorúan meg kell egyezniük.
A következő teszt meghiúsul, mert a kivétel üzenete nem felel meg:
Assert::exception(
fn() => throw new App\InvalidValueException('Zero value'),
App\InvalidValueException::class,
'Value is to low',
);
Az Assert::exception()
visszaadja a dobott kivételt, így a beágyazott kivételt is tesztelhetjük.
$e = Assert::exception(
fn() => throw new MyException('Something is wrong', 0, new RuntimeException),
MyException::class,
'Something is wrong',
);
Assert::type(RuntimeException::class, $e->getPrevious());
Assert::error (string $callable, int|string|array $type, ?string $message=null)
Ellenőrzi, hogy a $callable
függvény generálta-e a várt hibákat (azaz warningokat, notice-okat stb.).
$type
-ként adjuk meg az E_...
konstansok egyikét, például E_WARNING
. És ha megadjuk a
$message
-t, a hibaüzenetnek is meg kell felelnie a mintának. Például:
Assert::error(
fn() => $i++,
E_NOTICE,
'Undefined variable: i',
);
Ha a callback több hibát generál, mindegyiket pontos sorrendben kell várnunk. Ebben az esetben a $type
-ban egy
tömböt adunk át:
Assert::error(function () {
$a++;
$b++;
}, [
[E_NOTICE, 'Undefined variable: a'],
[E_NOTICE, 'Undefined variable: b'],
]);
Ha $type
-ként egy osztálynevet ad meg, ugyanúgy viselkedik, mint az
Assert::exception()
.
Assert::noError (callable $callable)
Ellenőrzi, hogy a $callable
függvény nem generált-e semmilyen warningot, hibát vagy kivételt. Hasznos olyan
kódrészletek tesztelésére, ahol nincs más assert.
Assert::match (string $pattern, $actual, ?string $description=null)
Az $actual
-nak meg kell felelnie a $pattern
mintának. Kétféle mintát használhatunk: reguláris
kifejezéseket vagy helyettesítő karaktereket.
Ha $pattern
-ként reguláris kifejezést adunk át, annak határolására ~
vagy #
kell
használni, más elválasztók nem támogatottak. Például egy teszt, ahol a $var
-nak csak hexadecimális
számjegyeket kell tartalmaznia:
Assert::match('#^[0-9a-f]$#i', $var);
A második változat hasonló a szokásos string összehasonlításhoz, de a $pattern
-ben különböző
helyettesítő karaktereket használhatunk:
%a%
egy vagy több karakter, kivéve a sorvégi karaktereket%a?%
nulla vagy több karakter, kivéve a sorvégi karaktereket%A%
egy vagy több karakter, beleértve a sorvégi karaktereket%A?%
nulla vagy több karakter, beleértve a sorvégi karaktereket%s%
egy vagy több szóköz karakter, kivéve a sorvégi karaktereket%s?%
nulla vagy több szóköz karakter, kivéve a sorvégi karaktereket%S%
egy vagy több karakter, kivéve a szóköz karaktereket%S?%
nulla vagy több karakter, kivéve a szóköz karaktereket%c%
bármilyen egy karakter, kivéve a sorvégi karaktert%d%
egy vagy több számjegy%d?%
nulla vagy több számjegy%i%
előjeles egész szám érték%f%
tizedesvesszős szám%h%
egy vagy több hexadecimális számjegy%w%
egy vagy több alfanumerikus karakter%%
a % karakter
Példák:
# Ismét teszt hexadecimális számra
Assert::match('%h%', $var);
# Fájl elérési útjának és sorszámának általánosítása
Assert::match('Error in file %a% on line %i%', $errorMessage);
Assert::matchFile (string $file, $actual, ?string $description=null)
Az assert azonos az Assert::match()-csal, de a minta a $file
fájlból töltődik
be. Ez hasznos nagyon hosszú stringek tesztelésére. A tesztfájl áttekinthető marad.
Assert::fail (string $message, $actual=null, $expected=null)
Ez az assert mindig meghiúsul. Néha egyszerűen hasznos. Opcionálisan megadhatjuk a várt és a tényleges értéket is.
Elvárások
Ha összetettebb struktúrákat szeretnénk összehasonlítani nem konstans elemekkel, a fenti assertok nem biztos, hogy
elegendőek. Például tesztelünk egy metódust, amely új felhasználót hoz létre, és annak attribútumait tömbként adja
vissza. A jelszó hash értékét nem ismerjük, de tudjuk, hogy hexadecimális stringnek kell lennie. És egy másik elemről
csak annyit tudunk, hogy DateTime
objektumnak kell lennie.
Ezekben a helyzetekben használhatjuk a Tester\Expect
-et az $expected
paraméteren belül az
Assert::equal()
és Assert::notEqual()
metódusokban, amelyek segítségével a struktúra könnyen
leírható.
use Tester\Expect;
Assert::equal([
'id' => Expect::type('int'), # egész számot várunk
'username' => 'milo',
'password' => Expect::match('%h%'), # mintának megfelelő stringet várunk
'created_at' => Expect::type(DateTime::class), # osztálypéldányt várunk
], User::create(123, 'milo', 'RandomPaSsWoRd'));
Az Expect
-tel szinte ugyanazokat az assertokat végezhetjük el, mint az Assert
-tel. Tehát
rendelkezésünkre állnak az Expect::same()
, Expect::match()
, Expect::count()
stb.
metódusok. Ráadásul láncolhatjuk őket:
Expect::type(MyIterator::class)->andCount(5); # MyIterator-t és 5 elemet várunk
Vagy írhatunk saját assert kezelőket.
Expect::that(function ($value) {
# false-t adunk vissza, ha az elvárás meghiúsul
});
Hibás assertok vizsgálata
Ha egy assert meghiúsul, a Tester kiírja, mi a hiba. Ha összetettebb struktúrákat hasonlítunk össze, a Tester dumpokat
hoz létre az összehasonlított értékekről, és elmenti őket az output
könyvtárba. Például egy képzeletbeli
Arrays.recursive.phpt
teszt meghiúsulása esetén a dumpok a következőképpen lesznek elmentve:
app/
└── tests/
├── output/
│ ├── Arrays.recursive.actual # tényleges érték
│ └── Arrays.recursive.expected # várt érték
│
└── Arrays.recursive.phpt # hibás teszt
A könyvtár nevét a Tester\Dumper::$dumpDir
segítségével módosíthatjuk.