Assertions
Les assertions sont utilisées pour confirmer qu'une valeur réelle correspond à une valeur attendue. Ce sont
des méthodes de la classe Tester\Assert
.
Choisissez les assertions les plus pertinentes. Il est préférable d'utiliser Assert::same($a, $b)
plutôt que
Assert::true($a === $b)
, car en cas d'échec, elle affiche un message d'erreur significatif. Dans le second cas,
seulement false should be true
ce qui ne nous dit rien sur le contenu des variables $a
et
$b
.
La plupart des assertions peuvent également avoir une description facultative dans le paramètre $description
,
qui sera affichée dans le message d'erreur si l'attente échoue.
Les exemples supposent la création d'un alias :
use Tester\Assert;
Assert::same ($expected, $actual, ?string $description=null)
$expected
doit être identique à $actual
. C'est la même chose que l'opérateur PHP
===
.
Assert::notSame ($expected, $actual, ?string $description=null)
L'opposé de Assert::same()
, donc la même chose que l'opérateur PHP !==
.
Assert::equal ($expected, $actual, ?string $description=null, bool $matchOrder=false, bool $matchIdentity=false)
$expected
doit être égal à $actual
. Contrairement à Assert::same()
, l'identité des
objets, l'ordre des paires clé ⇒ valeur dans les tableaux et les nombres décimaux légèrement différents sont ignorés, ce
qui peut être modifié en définissant $matchIdentity
et $matchOrder
.
Les cas suivants sont considérés comme identiques par equal()
, mais pas par same()
:
Assert::equal(0.3, 0.1 + 0.2);
Assert::equal($obj, clone $obj);
Assert::equal(
['first' => 11, 'second' => 22],
['second' => 22, 'first' => 11],
);
Attention cependant, les tableaux [1, 2]
et [2, 1]
ne sont pas considérés comme identiques, car
seul l'ordre des valeurs diffère, pas celui des paires clé ⇒ valeur. Le tableau [1, 2]
peut aussi s'écrire
[0 => 1, 1 => 2]
et sera donc considéré comme identique à [1 => 2, 0 => 1]
.
De plus, dans $expected
, on peut utiliser ce que l'on appelle des attentes.
Assert::notEqual ($expected, $actual, ?string $description=null)
L'opposé de Assert::equal()
.
Assert::contains ($needle, string|array $actual, ?string $description=null)
Si $actual
est une chaîne de caractères, elle doit contenir la sous-chaîne $needle
. Si c'est un
tableau, il doit contenir l'élément $needle
(comparaison stricte).
Assert::notContains ($needle, string|array $actual, ?string $description=null)
L'opposé de Assert::contains()
.
Assert::hasKey (string|int $needle, array $actual, ?string $description=null)
$actual
doit être un tableau et doit contenir la clé $needle
.
Assert::notHasKey (string|int $needle, array $actual, ?string $description=null)
$actual
doit être un tableau et ne doit pas contenir la clé $needle
.
Assert::true ($value, ?string $description=null)
$value
doit être true
, c'est-à-dire $value === true
.
Assert::truthy ($value, ?string $description=null)
$value
doit être vrai (truthy), c'est-à-dire qu'elle satisfait la condition if ($value) ...
.
Assert::false ($value, ?string $description=null)
$value
doit être false
, c'est-à-dire $value === false
.
Assert::falsey ($value, ?string $description=null)
$value
doit être faux (falsey), c'est-à-dire qu'elle satisfait la condition if (!$value) ...
.
Assert::null ($value, ?string $description=null)
$value
doit être null
, c'est-à-dire $value === null
.
Assert::notNull ($value, ?string $description=null)
$value
ne doit pas être null
, c'est-à-dire $value !== null
.
Assert::nan ($value, ?string $description=null)
$value
doit être Not a Number. Pour tester la valeur NAN, utilisez exclusivement Assert::nan()
. La
valeur NAN est très spécifique et les assertions Assert::same()
ou Assert::equal()
peuvent fonctionner
de manière inattendue.
Assert::count ($count, Countable|array $value, ?string $description=null)
Le nombre d'éléments dans $value
doit être $count
. C'est donc la même chose que
count($value) === $count
.
Assert::type (string|object $type, $value, ?string $description=null)
$value
doit être du type donné. Comme $type
, nous pouvons utiliser une chaîne :
array
list
– tableau indexé par une série ascendante de clés numériques à partir de zérobool
callable
float
int
null
object
resource
scalar
string
- nom de classe ou directement un objet, alors
$value instanceof $type
doit être vrai
Assert::exception (callable $callable, string $class, ?string $message=null, $code=null)
Lors de l'appel de $callable
, une exception de la classe $class
doit être levée. Si nous
spécifions $message
, le message de l'exception doit également correspondre au
modèle et si nous spécifions $code
, les codes doivent également correspondre strictement.
Le test suivant échouera car le message de l'exception ne correspond pas :
Assert::exception(
fn() => throw new App\InvalidValueException('Zero value'),
App\InvalidValueException::class,
'Value is too low',
);
Assert::exception()
retourne l'exception levée, ce qui permet de tester également une exception imbriquée.
$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)
Vérifie que l'appelable $callable
a généré les erreurs attendues (c.-à-d. avertissements, notices, etc.).
Comme $type
, nous indiquons l'une des constantes E_...
, par exemple E_WARNING
. Et si nous
indiquons $message
, le message d'erreur doit également correspondre au modèle. Par
exemple :
Assert::error(
fn() => $i++,
E_NOTICE,
'Undefined variable: i',
);
Si l'appelable génère plusieurs erreurs, nous devons toutes les attendre dans l'ordre exact. Dans ce cas, nous passons un
tableau dans $type
:
Assert::error(function () {
$a++;
$b++;
}, [
[E_NOTICE, 'Undefined variable: a'],
[E_NOTICE, 'Undefined variable: b'],
]);
Si vous indiquez un nom de classe comme $type
, elle se comporte comme
Assert::exception()
.
Assert::noError (callable $callable)
Vérifie que l'appelable $callable
n'a généré aucun avertissement, erreur ou exception. Utile pour tester des
fragments de code où aucune autre assertion n'est présente.
Assert::match (string $pattern, $actual, ?string $description=null)
$actual
doit correspondre au pattern $pattern
. Nous pouvons utiliser deux variantes de patterns : les
expressions régulières ou les caractères génériques.
Si nous passons une expression régulière comme $pattern
, nous devons utiliser ~
ou #
pour la délimiter, les autres délimiteurs ne sont pas pris en charge. Par exemple, un test où $var
ne doit
contenir que des chiffres hexadécimaux :
Assert::match('#^[0-9a-f]$#i', $var);
La seconde variante est similaire à la comparaison de chaînes classique, mais dans $pattern
, nous pouvons
utiliser divers caractères génériques :
%a%
un ou plusieurs caractères, sauf les caractères de fin de ligne%a?%
zéro ou plusieurs caractères, sauf les caractères de fin de ligne%A%
un ou plusieurs caractères, y compris les caractères de fin de ligne%A?%
zéro ou plusieurs caractères, y compris les caractères de fin de ligne%s%
un ou plusieurs espaces blancs, sauf les caractères de fin de ligne%s?%
zéro ou plusieurs espaces blancs, sauf les caractères de fin de ligne%S%
un ou plusieurs caractères, sauf les espaces blancs%S?%
zéro ou plusieurs caractères, sauf les espaces blancs%c%
n'importe quel caractère unique, sauf le caractère de fin de ligne%d%
un ou plusieurs chiffres%d?%
zéro ou plusieurs chiffres%i%
valeur entière signée%f%
nombre à virgule flottante%h%
un ou plusieurs chiffres hexadécimaux%w%
un ou plusieurs caractères alphanumériques%%
le caractère %
Exemples :
# Encore un test pour un nombre hexadécimal
Assert::match('%h%', $var);
# Généralisation du chemin du fichier et du numéro de ligne
Assert::match('Error in file %a% on line %i%', $errorMessage);
Assert::matchFile (string $file, $actual, ?string $description=null)
Cette assertion est identique à Assert::match(), mais le pattern est chargé depuis le fichier
$file
. C'est utile pour tester des chaînes très longues. Le fichier de test reste clair.
Assert::fail (string $message, $actual=null, $expected=null)
Cette assertion échoue systématiquement. C'est parfois utile. Facultativement, nous pouvons également indiquer la valeur attendue et la valeur réelle.
Attentes
Lorsque nous voulons comparer des structures plus complexes contenant des éléments non constants, les assertions ci-dessus
peuvent ne pas être suffisantes. Par exemple, nous testons une méthode qui crée un nouvel utilisateur et renvoie ses attributs
sous forme de tableau. Nous ne connaissons pas la valeur du hash du mot de passe, mais nous savons qu'il doit s'agir d'une chaîne
hexadécimale. Et pour un autre élément, nous savons seulement qu'il doit s'agir d'un objet DateTime
.
Dans ces situations, nous pouvons utiliser Tester\Expect
à l'intérieur du paramètre $expected
des
méthodes Assert::equal()
et Assert::notEqual()
, avec lesquelles la structure peut être facilement
décrite.
use Tester\Expect;
Assert::equal([
'id' => Expect::type('int'), # nous attendons un entier
'username' => 'milo',
'password' => Expect::match('%h%'), # nous attendons une chaîne correspondant au pattern
'created_at' => Expect::type(DateTime::class), # nous attendons une instance de la classe
], User::create(123, 'milo', 'RandomPaSsWoRd'));
Avec Expect
, nous pouvons effectuer quasiment les mêmes assertions qu'avec Assert
. Ainsi, les
méthodes Expect::same()
, Expect::match()
, Expect::count()
, etc. sont à notre disposition.
De plus, nous pouvons les chaîner :
Expect::type(MyIterator::class)->andCount(5); # nous attendons MyIterator et un nombre d'éléments de 5
Ou bien, nous pouvons écrire nos propres gestionnaires d'assertions.
Expect::that(function ($value) {
# nous retournons false si l'attente échoue
});
Examen des assertions erronées
Lorsqu'une assertion échoue, Tester indique où se situe l'erreur. Si nous comparons des structures plus complexes, Tester
crée des dumps des valeurs comparées et les enregistre dans le répertoire output
. Par exemple, en cas d'échec du
test fictif Arrays.recursive.phpt
, les dumps seront enregistrés comme suit :
app/
└── tests/
├── output/
│ ├── Arrays.recursive.actual # valeur actuelle
│ └── Arrays.recursive.expected # valeur attendue
│
└── Arrays.recursive.phpt # test échouant
Le nom du répertoire peut être modifié via Tester\Dumper::$dumpDir
.