Állítások

Az állítások azt bizonyítják, hogy egy tényleges érték megegyezik egy elvárt értékkel. Ezek a Tester\Assert metódusai.

Válassza ki a legpontosabb állításokat. Jobb a Assert::same($a, $b) mint a Assert::true($a === $b), mert hiba esetén értelmes hibaüzenetet jelenít meg. A második esetben csak false should be true kapunk, és ez semmit sem mond a $a és $b változók tartalmáról.

A legtöbb állításnak lehet egy opcionális $description is, amely megjelenik a hibaüzenetben, ha az elvárás sikertelen.

A példák feltételezik, hogy a következő osztály alias van definiálva:

use Tester\Assert;

Assert::same ($expected, $actual, ?string $description=null)

$expected azonosnak kell lennie a $actual címmel. Ez megegyezik a === PHP-operátorral.

Assert::notSame ($expected, $actual, ?string $description=null)

Ellentétes a Assert::same()-val , tehát megegyezik a !== PHP-operátorral.

Assert::equal ($expected, $actual, ?string $description=null, bool $matchOrder=false, bool $matchIdentity=false)

$expected ugyanannak kell lennie, mint a $actual. A Assert::same()-től eltérően az objektum azonosságát, a kulcspárok ⇒ érték sorrendjét a tömbökben, valamint a minimálisan eltérő decimális számokat figyelmen kívül hagyja, ami a $matchIdentity és a $matchOrder beállításával módosítható.

A következő esetek a equal() szempontjából azonosak, 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, a tömb [1, 2] és a [2, 1] nem egyenlőek, mert csak az értékek sorrendje különbözik, a kulcs ⇒ érték párok nem. A tömb [1, 2] írható úgy is, hogy [0 => 1, 1 => 2] és így [1 => 2, 0 => 1] egyenlőnek tekintjük.

Használhatjuk az úgynevezett elvárásokat is a $expected.

Assert::notEqual ($expected, $actual, ?string $description=null)

Ellentétben a Assert::equal().

Assert::contains ($needle, string|array $actual, ?string $description=null)

Ha a $actual egy karakterlánc, akkor tartalmaznia kell a $needle részláncot. Ha tömb, akkor a $needle elemet kell tartalmaznia (szigorúan összehasonlításra kerül).

Assert::notContains ($needle, string|array $actual, ?string $description=null)

A Assert::contains() ellentéte.

Assert::hasKey (string|int $needle, array $actual, ?string $description=null)

$actual tömbnek kell lennie, és tartalmaznia kell a $needle kulcsot.

Assert::notHasKey (string|int $needle, array $actual, ?string $description=null)

$actual tömbnek kell lennie, és nem tartalmazhatja a $needle kulcsot.

Assert::true ($value, ?string $description=null)

$value a true kell, hogy legyen, tehát $value === true.

Assert::truthy ($value, ?string $description=null)

$value igaznak kell lennie, tehát teljesíti a if ($value) ... feltételt.

Assert::false ($value, ?string $description=null)

$value kell lennie false, tehát $value === false.

Assert::falsey ($value, ?string $description=null)

$value hamisnak kell lennie, tehát teljesíti a if (!$value) ... feltételt.

Assert::null ($value, ?string $description=null)

$value a null kell, hogy legyen, tehát $value === null.

Assert::notNull ($value, ?string $description=null)

$value nem lehet null, tehát $value !== null.

Assert::nan ($value, ?string $description=null)

$value nem lehet szám. A NAN teszteléshez csak a Assert::nan() címet használja. A NAN érték nagyon specifikus, és a Assert::same() vagy a Assert::equal() állítások kiszámíthatatlanul viselkedhetnek.

Assert::count ($count, Countable|array $value, ?string $description=null)

A $value elemszámának a $count kell lennie. Tehát ugyanaz, mint a count($value) === $count.

Assert::type (string|object $type, $value, ?string $description=null)

$value adott típusúnak kell lennie. Mint $type használhatjuk a stringet:

  • array
  • list – nullától kezdve a numerikus kulcsok növekvő sorrendjében indexelt tömb.
  • bool
  • callable
  • float
  • int
  • null
  • object
  • resource
  • scalar
  • string
  • osztály nevét vagy objektumot közvetlenül, akkor át kell adnia $value instanceof $type

Assert::exception (callable $callable, string $class, ?string $message=null, $code=null)

A $callable meghívásakor egy $class példányú kivételt kell dobni. Ha átadjuk a $message címet, a kivétel üzenetének meg kell egyeznie. És ha átadjuk a $code, a kivétel kódjának meg kell egyeznie.

Például ez a teszt sikertelen, mert a kivétel üzenete nem egyezik:

Assert::exception(
	fn() => throw new App\InvalidValueException('Zero value'),
	App\InvalidValueException::class,
	'Value is to low',
);

A Assert::exception() egy dobott kivételt ad vissza, így tesztelhet egy beágyazott kivételt.

$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 meghívása a várt hibákat (azaz figyelmeztetéseket, értesítéseket stb.) generálja. Mint $type megadjuk a E_..., például a E_WARNING konstansok egyikét. És ha átadjuk a $message, a hibaüzenetnek is meg kell felelnie a mintának. Például:

Assert::error(
	fn() => $i++,
	E_NOTICE,
	'Undefined variable: i',
);

Ha a visszahívás több hibát generál, akkor mindegyiket a pontos sorrendben kell várnunk. Ebben az esetben a tömböt a $type címen adjuk át:

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

Ha a $type az osztály neve, akkor ez az állítás ugyanúgy viselkedik, mint a Assert::exception().

Assert::noError (callable $callable)

Ellenőrzi, hogy a $callable függvény nem dob-e PHP figyelmeztetést/értesítést/hibát vagy kivételt. Hasznos egy olyan kódrészlet teszteléséhez, ahol nincs más állítás.

Assert::match (string $pattern, $actual, ?string $description=null)

$actual kell, hogy egyezzen a $pattern. A minták két változatát használhatjuk: a reguláris kifejezéseket vagy a vadkártyákat.

Ha egy reguláris kifejezést adunk át a $pattern címen, akkor a ~ or # címet kell használnunk az elhatároláshoz. Más elválasztójelek nem támogatottak. Például a teszt, ahol a $var csak hexadecimális számjegyeket tartalmazhat:

Assert::match('#^[0-9a-f]$#i', $var);

A másik változat hasonló a string-összehasonlításhoz, de használhatunk néhány vad karaktert a $pattern:

  • %a% egy vagy több bármi, kivéve a sor végi karaktereket.
  • %a?% nulla vagy több bármi más, kivéve a sor végi karaktereket.
  • %A% egy vagy több bármi, beleértve a sor végi karaktereket is.
  • %A?% nulla vagy több bármiből, beleértve a sor végi karaktereket is.
  • %s% egy vagy több szóköz karakter, kivéve a sor végi karaktereket.
  • %s?% nulla vagy több szóköz karakter, kivéve a sor végi karaktereket
  • %S% egy vagy több karakter, kivéve a szóközöket.
  • %S?% nulla vagy több karakter, kivéve a szóközöket.
  • %c% egyetlen bármilyen karakter (kivéve a sor végét)
  • %d% egy vagy több számjegy
  • %d?% nulla vagy több számjegy
  • %i% előjeles egész érték
  • %f% lebegőpontos szám
  • %h% egy vagy több HEX számjegy
  • %w% egy vagy több alfanumerikus karakter
  • %% egy % karakter

Példák:

# Again, hexadecimal number test
Assert::match('%h%', $var);

# Generalized path to file and line number
Assert::match('Error in file %a% on line %i%', $errorMessage);

Assert::matchFile (string $file, $actual, ?string $description=null)

Az állítás megegyezik az Assert::match()-vel, de a minta a $file oldalról töltődik be. Nagyon hosszú karakterláncok teszteléséhez hasznos. A tesztfájl olvashatóan áll.

Assert::fail (string $message, $actual=null, $expected=null)

Ez az állítás mindig sikertelen. Csak praktikus. Opcionálisan átadhatjuk a várható és a tényleges értékeket.

Várakozások

Ha összetettebb, nem konstans elemeket tartalmazó struktúrákat akarunk összehasonlítani, a fenti állítások nem biztos, hogy elegendőek. Például tesztelünk egy olyan metódust, amely létrehoz egy új felhasználót, és az attribútumait tömbként adja vissza. A jelszó hash-értékét nem ismerjük, de azt tudjuk, hogy annak hexadecimális karakterláncnak kell lennie. A következő elemről pedig csak annyit tudunk, hogy annak egy objektumnak kell lennie: DateTime.

Ezekben az esetekben a Assert::equal() és a Assert::notEqual() metódusok $expected paraméterén belül használhatjuk a Tester\Expect -t, amivel könnyen leírhatjuk a struktúrát.

use Tester\Expect;

Assert::equal([
	'id' => Expect::type('int'),                   # we expect an integer
	'username' => 'milo',
	'password' => Expect::match('%h%'),            # we expect a string matching pattern
	'created_at' => Expect::type(DateTime::class), # we expect an instance of the class
], User::create(123, 'milo', 'RandomPaSsWoRd'));

A Expect segítségével szinte ugyanazokat az állításokat tehetjük, mint a Assert segítségével. Így olyan metódusaink vannak, mint a Expect::same(), Expect::match(), Expect::count(), stb. Ezen kívül láncolhatjuk őket, mint:

Expect::type(MyIterator::class)->andCount(5);  # we expect MyIterator and items count is 5

Vagy írhatunk saját állításkezelőket.

Expect::that(function ($value) {
	# return false if expectation fails
});

Sikertelen állítások vizsgálata

A Tester megmutatja, hol van a hiba, ha egy állítás sikertelen. Amikor összetett struktúrákat hasonlítunk össze, a Tester dumps-ot készít az összehasonlított értékekről, és elmenti azokat a output könyvtárba. Például amikor a képzeletbeli Arrays.recursive.phpt teszt sikertelen, a dumps a következőképpen kerül elmentésre:

app/
└── tests/
	├── output/
	│   ├── Arrays.recursive.actual    # actual value
	│   └── Arrays.recursive.expected  # expected value
	│
	└── Arrays.recursive.phpt          # failing test

A könyvtár nevét a Tester\Dumper::$dumpDir címen változtathatjuk meg.