Afirmații
Afirmațiile sunt utilizate pentru a afirma că o valoare reală corespunde unei valori așteptate. Acestea sunt
metode ale aplicației Tester\Assert
.
Alegeți cele mai exacte aserțiuni. Este mai bună Assert::same($a, $b)
decât
Assert::true($a === $b)
, deoarece afișează un mesaj de eroare semnificativ în caz de eșec. În cel de-al doilea
caz, obținem doar false should be true
și nu spune nimic despre conținutul variabilelor $a și $b.
Cele mai multe aserțiuni pot avea, de asemenea, un $description
opțional care apare în mesajul de eroare în
cazul în care așteptarea eșuează.
Exemplele presupun că este definit următorul alias de clasă:
use Tester\Assert;
Assert::same($expected, $actual, ?string $description=null)
$expected
trebuie să fie aceeași cu $actual
. Este același lucru cu operatorul PHP
===
.
Assert::notSame($expected, $actual, ?string $description=null)
Opusul lui Assert::same()
, deci este același lucru cu operatorul PHP !==
.
Assert::equal($expected, $actual, ?string $description=null, bool $matchOrder=false, bool $matchIdentity=false)
$expected
trebuie să fie același cu $actual
. Spre deosebire de Assert::same()
,
identitatea obiectului, ordinea perechilor cheie ⇒ valoare în array-uri și numerele zecimale marginal diferite sunt ignorate,
care pot fi modificate prin setarea $matchIdentity
și $matchOrder
.
Următoarele cazuri sunt identice din punctul de vedere al equal()
, dar nu și pentru same()
:
Assert::equal(0.3, 0.1 + 0.2);
Assert::equal($obj, clone $obj);
Assert::equal(
['first' => 11, 'second' => 22],
['second' => 22, 'first' => 11],
);
Cu toate acestea, atenție, matricea [1, 2]
și [2, 1]
nu sunt egale, deoarece doar ordinea valorilor
diferă, nu și perechile cheie ⇒ valoare. Tabloul [1, 2]
poate fi scris și sub forma
[0 => 1, 1 => 2]
și deci [1 => 2, 0 => 1]
va fi considerat egal.
Puteți utiliza, de asemenea, așa-numitele așteptări în $expected
.
Assert::notEqual($expected, $actual, ?string $description=null)
Opusul lui Assert::equal()
.
Assert::contains($needle, string|array $actual, ?string $description=null)
Dacă $actual
este un șir de caractere, acesta trebuie să conțină subșirul $needle
. Dacă este
o matrice, trebuie să conțină elementul $needle
(acesta este comparat strict).
Assert::notContains($needle, string|array $actual, ?string $description=null)
Opusul lui Assert::contains()
.
Assert::hasKey(string|int $needle, array $actual, ?string $description=null)
$actual
trebuie să fie o matrice și să conțină cheia $needle
.
Assert::notHasKey(string|int $needle, array $actual, ?string $description=null)
$actual
trebuie să fie o matrice și să nu conțină cheia $needle
.
Assert::true($value, ?string $description=null)
$value
trebuie să fie true
, deci $value === true
.
Assert::truthy($value, ?string $description=null)
$value
trebuie să fie adevărat, deci satisface condiția if ($value) ...
.
Assert::false($value, ?string $description=null)
$value
trebuie să fie false
, deci $value === false
.
Assert::falsey($value, ?string $description=null)
$value
trebuie să fie falsey, deci îndeplinește condiția if (!$value) ...
.
Assert::null($value, ?string $description=null)
$value
trebuie să fie null
, deci $value === null
.
Assert::notNull($value, ?string $description=null)
$value
nu trebuie să fie null
, deci $value !== null
.
Assert::nan($value, ?string $description=null)
$value
trebuie să nu fie un număr. Utilizați numai Assert::nan()
pentru testarea NAN. Valoarea NAN
este foarte specifică, iar afirmațiile Assert::same()
sau Assert::equal()
se pot comporta în mod
imprevizibil.
Assert::count($count, Countable|array $value, ?string $description=null)
Numărul de elemente din $value
trebuie să fie $count
. Deci la fel ca
count($value) === $count
.
Assert::type(string|object $type, $value, ?string $description=null)
$value
trebuie să fie de un anumit tip. La fel ca $type
putem folosi string:
array
list
– matrice indexată în ordine crescătoare a cheilor numerice de la zero.bool
callable
float
int
null
object
resource
scalar
string
- numele clasei sau obiectul direct, atunci trebuie să treacă
$value instanceof $type
Assert::exception(callable $callable, string $class, ?string $message=null, $code=null)
La invocarea $callable
trebuie să se arunce o excepție de instanță $class
. Dacă se trece
$message
, mesajul excepției trebuie să corespundă. Iar dacă se trece
$code
, codul excepției trebuie să fie același.
De exemplu, acest test eșuează deoarece mesajul excepției nu se potrivește:
Assert::exception(
fn() => throw new App\InvalidValueException('Zero value'),
App\InvalidValueException::class,
'Value is to low',
);
Site-ul Assert::exception()
returnează o excepție lansată, astfel încât puteți testa o excepție
imbricata.
$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)
Verifică dacă invocarea $callable
generează erorile așteptate (adică avertismente, notificări etc.). Ca
$type
se specifică una dintre constantele E_...
, de exemplu E_WARNING
. Iar dacă se trece
$message
, mesajul de eroare trebuie să corespundă și el modelului. De exemplu:
Assert::error(
fn() => $i++,
E_NOTICE,
'Undefined variable: i',
);
Dacă callback-ul generează mai multe erori, trebuie să le așteptăm pe toate în ordinea exactă. În acest caz, trecem
matricea în $type
:
Assert::error(function () {
$a++;
$b++;
}, [
[E_NOTICE, 'Undefined variable: a'],
[E_NOTICE, 'Undefined variable: b'],
]);
Dacă $type
este numele clasei, această afirmație se comportă la fel ca
Assert::exception()
.
Assert::noError(callable $callable)
Verifică dacă funcția $callable
nu aruncă niciun avertisment/notificare/error sau excepție PHP. Este utilă
pentru testarea unei bucăți de cod în care nu există nicio altă afirmație.
Assert::match(string $pattern, $actual, ?string $description=null)
$actual
trebuie să se potrivească cu $pattern
. Putem utiliza două variante de tipare: expresii
regulate sau caractere sălbatice.
Dacă trecem o expresie regulată ca $pattern
, trebuie să folosim ~
or #
pentru a
o delimita. Alte delimitatoare nu sunt acceptate. De exemplu, testul în care $var
trebuie să conțină numai cifre
hexazecimale:
Assert::match('#^[0-9a-f]$#i', $var);
Cealaltă variantă este similară cu compararea șirurilor de caractere, dar putem folosi unele caractere wild în
$pattern
:
%a%
unul sau mai multe din orice, cu excepția caracterelor de sfârșit de linie%a?%
zero sau mai multe de orice, cu excepția caracterelor de sfârșit de linie%A%
unul sau mai multe din orice, inclusiv caracterele de sfârșit de linie%A?%
zero sau mai multe de orice, inclusiv caracterele de sfârșit de linie%s%
unul sau mai multe caractere de spațiu alb, cu excepția caracterelor de sfârșit de rând%s?%
zero sau mai multe caractere de spațiu alb, cu excepția caracterelor de sfârșit de rând%S%
unul sau mai multe caractere, cu excepția spațiului alb%S?%
zero sau mai multe caractere, cu excepția spațiului alb%c%
un singur caracter de orice fel (cu excepția celor de sfârșit de rând)%d%
una sau mai multe cifre%d?%
zero sau mai multe cifre%i%
valoare întreagă cu semn%f%
număr în virgulă mobilă%h%
una sau mai multe cifre HEX%w%
unul sau mai multe caractere alfanumerice%%
un caracter %
Exemple:
# 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)
Afirmația este identică cu Assert::match(), dar modelul este încărcat din
$file
. Este utilă pentru testarea șirurilor foarte lungi. Fișierul de test stă în picioare lizibil.
Assert::fail(string $message, $actual=null, $expected=null)
Această afirmație eșuează întotdeauna. Este doar la îndemână. Putem trece opțional valorile așteptate și cele reale.
Așteptări
Dacă dorim să comparăm structuri mai complexe, cu elemente neconstante, afirmațiile de mai sus ar putea să nu fie
suficiente. De exemplu, testăm o metodă care creează un nou utilizator și îi returnează atributele sub forma unui tablou.
Nu cunoaștem valoarea hash a parolei, dar știm că aceasta trebuie să fie un șir hexazecimal. Și singurul lucru pe care îl
știm despre următorul element este că trebuie să fie un obiect DateTime
.
În aceste cazuri, putem utiliza Tester\Expect
în interiorul parametrului $expected
al metodelor
Assert::equal()
și Assert::notEqual()
, care poate fi folosit pentru a descrie cu ușurință
structura.
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'));
Cu Expect
, putem face aproape aceleași afirmații ca și cu Assert
. Astfel, avem metode precum
Expect::same()
, Expect::match()
, Expect::count()
, etc. În plus, putem să le înlănțuim
astfel:
Expect::type(MyIterator::class)->andCount(5); # we expect MyIterator and items count is 5
Sau, putem scrie propriile gestionari de afirmații.
Expect::that(function ($value) {
# return false if expectation fails
});
Investigarea aserțiunilor eșuate
Tester arată unde se află eroarea atunci când o aserțiune eșuează. Atunci când comparăm structuri complexe, Tester
creează descărcări ale valorilor comparate și le salvează în directorul output
. De exemplu, atunci când testul
imaginar Arrays.recursive.phpt
eșuează, dumps-urile vor fi salvate după cum urmează:
app/
└── tests/
├── output/
│ ├── Arrays.recursive.actual # actual value
│ └── Arrays.recursive.expected # expected value
│
└── Arrays.recursive.phpt # failing test
Putem schimba numele directorului prin Tester\Dumper::$dumpDir
.