Nette Documentation Preview

syntax
Assertok
********

.[perex]
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:

```php
use Tester\Assert;
```


Assert::same($expected, $actual, ?string $description=null) .[method]
---------------------------------------------------------------------
Az `$expected`-nek azonosnak kell lennie az `$actual`-lal. Ugyanaz, mint a PHP `===` operátora.


Assert::notSame($expected, $actual, ?string $description=null) .[method]
------------------------------------------------------------------------
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) .[method]
-------------------------------------------------------------------------------------------------------------------------
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:

```php
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) .[method]
-------------------------------------------------------------------------
Az `Assert::equal()` ellentéte.


Assert::contains($needle, string|array $actual, ?string $description=null) .[method]
------------------------------------------------------------------------------------
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) .[method]
---------------------------------------------------------------------------------------
Az `Assert::contains()` ellentéte.


Assert::hasKey(string|int $needle, array $actual, ?string $description=null) .[method]{data-version:2.4}
--------------------------------------------------------------------------------------------------------
Az `$actual`-nak tömbnek kell lennie, és tartalmaznia kell a `$needle` kulcsot.


Assert::notHasKey(string|int $needle, array $actual, ?string $description=null) .[method]{data-version:2.4}
-----------------------------------------------------------------------------------------------------------
Az `$actual`-nak tömbnek kell lennie, és nem tartalmazhatja a `$needle` kulcsot.


Assert::true($value, ?string $description=null) .[method]
---------------------------------------------------------
Az `$value`-nak `true`-nak kell lennie, tehát `$value === true`.


Assert::truthy($value, ?string $description=null) .[method]
-----------------------------------------------------------
Az `$value`-nak igaznak kell lennie (truthy), tehát teljesíti az `if ($value) ...` feltételt.


Assert::false($value, ?string $description=null) .[method]
----------------------------------------------------------
Az `$value`-nak `false`-nak kell lennie, tehát `$value === false`.


Assert::falsey($value, ?string $description=null) .[method]
-----------------------------------------------------------
Az `$value`-nak hamisnak kell lennie (falsey), tehát teljesíti az `if (!$value) ...` feltételt.


Assert::null($value, ?string $description=null) .[method]
---------------------------------------------------------
Az `$value`-nak `null`-nak kell lennie, tehát `$value === null`.


Assert::notNull($value, ?string $description=null) .[method]
------------------------------------------------------------
Az `$value`-nak nem szabad `null`-nak lennie, tehát `$value !== null`.


Assert::nan($value, ?string $description=null) .[method]
--------------------------------------------------------
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) .[method]
----------------------------------------------------------------------------------
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) .[method]
------------------------------------------------------------------------------
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ömb
- `bool`
- `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) .[method]
-------------------------------------------------------------------------------------------------
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 |#Assert::match], é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:

```php
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.

```php
$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) .[method]
----------------------------------------------------------------------------------------
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 |#Assert::match]. Például:

```php
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:

```php
Assert::error(function () {
	$a++;
	$b++;
}, [
	[E_NOTICE, 'Undefined variable: a'],
	[E_NOTICE, 'Undefined variable: b'],
]);
```

.[note]
Ha `$type`-ként egy osztálynevet ad meg, ugyanúgy viselkedik, mint az `Assert::exception()`.


Assert::noError(callable $callable) .[method]
---------------------------------------------
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) .[method]
----------------------------------------------------------------------------
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:

```php
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:

```php
# 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) .[method]
-----------------------------------------------------------------------------
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) .[method]
---------------------------------------------------------------------
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ó.

```php
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:

```php
Expect::type(MyIterator::class)->andCount(5);  # MyIterator-t és 5 elemet várunk
```

Vagy írhatunk saját assert kezelőket.

```php
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.

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ömb
  • bool
  • 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.