Asercije
Asercije se uporabljajo za potrditev, da dejanska vrednost ustreza pričakovani vrednosti. Gre za metode razreda
Tester\Assert
.
Izbirajte čim bolj primerne asercije. Bolje je Assert::same($a, $b)
kot Assert::true($a === $b)
, ker
ob neuspehu prikaže smiselno sporočilo o napaki. V drugem primeru samo false should be true
, kar nam o vsebini
spremenljivk $a
in $b
nič ne pove.
Večina asercij lahko ima tudi neobvezen opis v parametru $description
, ki se prikaže v sporočilu o napaki,
če pričakovanje ne uspe.
Primeri predpostavljajo ustvarjen alias:
use Tester\Assert;
Assert::same ($expected, $actual, ?string $description=null)
$expected
mora biti identičen z $actual
. Enako kot PHP operator ===
.
Assert::notSame ($expected, $actual, ?string $description=null)
Nasprotje Assert::same()
, torej enako kot PHP operator !==
.
Assert::equal ($expected, $actual, ?string $description=null, bool $matchOrder=false, bool $matchIdentity=false)
$expected
mora biti enak z $actual
. Za razliko od Assert::same()
se ignorira identiteta
objektov, vrstni red parov ključ ⇒ vrednost v poljih in marginalno različna decimalna števila, kar je mogoče spremeniti
z nastavitvijo $matchIdentity
in $matchOrder
.
Naslednji primeri so enaki z vidika equal()
, vendar ne same()
:
Assert::equal(0.3, 0.1 + 0.2);
Assert::equal($obj, clone $obj);
Assert::equal(
['first' => 11, 'second' => 22],
['second' => 22, 'first' => 11],
);
Vendar pozor, polji [1, 2]
in [2, 1]
nista enaki, ker se razlikujeta samo v vrstnem redu vrednosti,
ne pa parov ključ ⇒ vrednost. Polje [1, 2]
lahko zapišemo tudi kot [0 => 1, 1 => 2]
in za
enako se zato bo štelo [1 => 2, 0 => 1]
.
Nadalje je mogoče v $expected
uporabiti t.i. pričakovanja.
Assert::notEqual ($expected, $actual, ?string $description=null)
Nasprotje Assert::equal()
.
Assert::contains ($needle, string|array $actual, ?string $description=null)
Če je $actual
niz, mora vsebovati podniz $needle
. Če je polje, mora vsebovati element
$needle
(primerja se strogo).
Assert::notContains ($needle, string|array $actual, ?string $description=null)
Nasprotje Assert::contains()
.
Assert::hasKey (string|int $needle, array $actual, ?string $description=null)
$actual
mora biti polje in mora vsebovati ključ $needle
.
Assert::notHasKey (string|int $needle, array $actual, ?string $description=null)
$actual
mora biti polje in ne sme vsebovati ključa $needle
.
Assert::true ($value, ?string $description=null)
$value
mora biti true
, torej $value === true
.
Assert::truthy ($value, ?string $description=null)
$value
mora biti resničen, torej izpolni pogoj if ($value) ...
.
Assert::false ($value, ?string $description=null)
$value
mora biti false
, torej $value === false
.
Assert::falsey ($value, ?string $description=null)
$value
mora biti neresničen, torej izpolni pogoj if (!$value) ...
.
Assert::null ($value, ?string $description=null)
$value
mora biti null
, torej $value === null
.
Assert::notNull ($value, ?string $description=null)
$value
ne sme biti null
, torej $value !== null
.
Assert::nan ($value, ?string $description=null)
$value
mora biti Not a Number. Za testiranje NAN vrednosti uporabljajte izključno Assert::nan()
.
Vrednost NAN je zelo specifična in aserciji Assert::same()
ali Assert::equal()
lahko delujeta
nepričakovano.
Assert::count ($count, Countable|array $value, ?string $description=null)
Število elementov v $value
mora biti $count
. Torej enako kot
count($value) === $count
.
Assert::type (string|object $type, $value, ?string $description=null)
$value
mora biti danega tipa. Kot $type
lahko uporabimo niz:
array
list
– polje, indeksirano po naraščajočem zaporedju numeričnih ključev od ničbool
callable
float
int
null
object
resource
scalar
string
- ime razreda ali neposredno objekt, potem mora biti
$value instanceof $type
Assert::exception (callable $callable, string $class, ?string $message=null, $code=null)
Pri klicu $callable
mora biti sprožena izjema razreda $class
. Če navedemo $message
,
mora ustrezati vzorcu tudi sporočilo izjeme in če navedemo $code
, se morata strogo
ujemati tudi kodi.
Naslednji test ne uspe, ker ne ustreza sporočilo izjeme:
Assert::exception(
fn() => throw new App\InvalidValueException('Vrednost je prenizka'),
App\InvalidValueException::class,
'Vrednost je prenizka',
);
Assert::exception()
vrača sproženo izjemo, lahko tako testiramo tudi ugnezdeno izjemo.
$e = Assert::exception(
fn() => throw new MyException('Nekaj je narobe', 0, new RuntimeException),
MyException::class,
'Nekaj je narobe',
);
Assert::type(RuntimeException::class, $e->getPrevious());
Assert::error (string $callable, int|string|array $type, ?string $message=null)
Preverja, da funkcija $callable
generira pričakovane napake (tj. opozorila, obvestila itd). Kot
$type
navedemo eno od konstant E_...
, torej na primer E_WARNING
. In če navedemo
$message
, mora ustrezati vzorcu tudi sporočilo o napaki. Na primer:
Assert::error(
fn() => $i++,
E_NOTICE,
'Undefined variable: i',
);
Če callback generira več napak, jih moramo vse pričakovati v točnem vrstnem redu. V takem primeru predamo v
$type
polje:
Assert::error(function () {
$a++;
$b++;
}, [
[E_NOTICE, 'Undefined variable: a'],
[E_NOTICE, 'Undefined variable: b'],
]);
Če kot $type
navedete ime razreda, se obnaša enako kot Assert::exception()
.
Assert::noError (callable $callable)
Preverja, da funkcija $callable
ni generirala nobenega opozorila, napake ali izjeme. Uporabno za testiranje
koščkov kode, kjer ni nobene druge asercije.
Assert::match (string $pattern, $actual, ?string $description=null)
$actual
mora ustrezati vzorcu $pattern
. Uporabimo lahko dve varianti vzorcev: regularne izraze ali
nadomestne znake.
Če kot $pattern
predamo regularni izraz, moramo za njegovo omejitev uporabiti ~
ali #
,
drugi ločilniki niso podprti. Na primer test, kjer $var
mora vsebovati samo šestnajstiške števke:
Assert::match('#^[0-9a-f]$#i', $var);
Druga varianta je podobna običajnemu primerjanju nizov, vendar lahko v $pattern
uporabimo različne
nadomestne znake:
%a%
en ali več znakov, razen znakov konca vrstice%a?%
noben ali več znakov, razen znakov konca vrstice%A%
en ali več znakov, vključno z znaki konca vrstice%A?%
noben ali več znakov, vključno z znaki konca vrstice%s%
en ali več belih znakov, razen znakov konca vrstice%s?%
noben ali več belih znakov, razen znakov konca vrstice%S%
en ali več znakov, razen belih znakov%S?%
noben ali več znakov, razen belih znakov%c%
katerikoli en znak, razen znaka konca vrstice%d%
ena ali več števk%d?%
nobena ali več števk%i%
predznačena celoštevilska vrednost%f%
število z decimalno vejico%h%
ena ali več šestnajstiških števk%w%
en ali več alfanumeričnih znakov%%
znak %
Primeri:
# Ponovno test za šestnajstiško število
Assert::match('%h%', $var);
# Posplošitev poti do datoteke in številke vrstice
Assert::match('Napaka v datoteki %a% v vrstici %i%', $errorMessage);
Assert::matchFile (string $file, $actual, ?string $description=null)
Asercija je identična z Assert::match(), vendar se vzorec nalaga iz datoteke
$file
. To je uporabno za testiranje zelo dolgih nizov. Datoteka s testom ostane pregledna.
Assert::fail (string $message, $actual=null, $expected=null)
Ta asercija vedno ne uspe. Včasih je to preprosto uporabno. Neobvezno lahko navedemo tudi pričakovano in dejansko vrednost.
Pričakovanja
Ko želimo primerjati bolj zapletene strukture z nekonstantnimi elementi, morda zgornje asercije ne bodo zadostovale. Na
primer testiramo metodo, ki ustvari novega uporabnika in vrne njegove atribute kot polje. Vrednosti hasha gesla ne poznamo, vendar
vemo, da mora biti šestnajstiški niz. In o drugem elementu vemo samo, da mora biti objekt DateTime
.
V teh situacijah lahko uporabimo Tester\Expect
znotraj $expected
parametra metod
Assert::equal()
in Assert::notEqual()
, s pomočjo katerih lahko strukturo enostavno opišemo.
use Tester\Expect;
Assert::equal([
'id' => Expect::type('int'), # pričakujemo celo število
'username' => 'milo',
'password' => Expect::match('%h%'), # pričakujemo niz, ki ustreza vzorcu
'created_at' => Expect::type(DateTime::class), # pričakujemo instanco razreda
], User::create(123, 'milo', 'RandomPaSsWoRd'));
Z Expect
lahko izvajamo skoraj enake asercije kot z Assert
. Torej so nam na voljo metode
Expect::same()
, Expect::match()
, Expect::count()
itd. Poleg tega jih lahko verižimo:
Expect::type(MyIterator::class)->andCount(5); # pričakujemo MyIterator in število elementov 5
Ali pa lahko pišemo lastne obdelovalce asercij.
Expect::that(function ($value) {
# vrnemo false, če pričakovanje ne uspe
});
Raziskovanje napačnih asercij
Ko asercija ne uspe, Tester izpiše, v čem je napaka. Če primerjamo bolj zapletene strukture, Tester ustvari izpise
primerjanih vrednosti in jih shrani v imenik output
. Na primer pri neuspehu izmišljenega testa
Arrays.recursive.phpt
bodo izpisi shranjeni na naslednji način:
app/
└── tests/
├── output/
│ ├── Arrays.recursive.actual # dejanska vrednost
│ └── Arrays.recursive.expected # pričakovana vrednost
│
└── Arrays.recursive.phpt # neuspešen test
Ime imenika lahko spremenimo preko Tester\Dumper::$dumpDir
.