Assertions
Les assertions sont utilisées pour affirmer qu'une valeur réelle correspond à une valeur attendue. Ce sont des
méthodes de l'application Tester\Assert
.
Choisissez les assertions les plus précises. Il est préférable d'utiliser Assert::same($a, $b)
plutôt que
Assert::true($a === $b)
car il affiche un message d'erreur significatif en cas d'échec. Dans le deuxième cas, nous
obtenons uniquement false should be true
et il ne dit rien sur le contenu des variables $a et $b.
La plupart des assertions peuvent également avoir une option $description
qui apparaît dans le message d'erreur
si l'attente échoue.
Les exemples supposent que l'alias de classe suivant est défini :
use Tester\Assert;
Assert::same ($expected, $actual, ?string $description=null)
$expected
doit être le même que $actual
. Il est identique à l'opérateur PHP ===
.
Assert::notSame ($expected, $actual, ?string $description=null)
Opposé à Assert::same()
, il est donc identique à l'opérateur PHP !==
.
Assert::equal ($expected, $actual, ?string $description=null, bool $matchOrder=false, bool $matchIdentity=false)
$expected
doit être le même que $actual
. Contrairement à Assert::same()
, l'identité
de l'objet, l'ordre des paires de clés ⇒ valeur dans les tableaux, et les nombres décimaux légèrement différents sont
ignorés, ce qui peut être modifié en paramétrant $matchIdentity
et $matchOrder
.
Les cas suivants sont identiques du point de vue de equal()
, mais pas pour same()
:
Assert::equal(0.3, 0.1 + 0.2);
Assert::equal($obj, clone $obj);
Assert::equal(
['first' => 11, 'second' => 22],
['second' => 22, 'first' => 11],
);
Cependant, attention, le tableau [1, 2]
et [2, 1]
ne sont pas égaux, car seul l'ordre des valeurs
diffère, pas les paires clé ⇒ valeur. Le tableau [1, 2]
peut aussi être écrit comme
[0 => 1, 1 => 2]
et donc [1 => 2, 0 => 1]
seront considérés comme égaux.
Vous pouvez également utiliser ce que l'on appelle les attentes dans
$expected
.
Assert::notEqual ($expected, $actual, ?string $description=null)
A 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
(il est comparé strictement).
Assert::notContains ($needle, string|array $actual, ?string $description=null)
Opposé à 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
, donc $value === true
.
Assert::truthy ($value, ?string $description=null)
$value
doit être véridique, donc il satisfait la condition if ($value) ...
.
Assert::false ($value, ?string $description=null)
$value
doit être false
, donc $value === false
.
Assert::falsey ($value, ?string $description=null)
$value
doit être faux, donc il remplit la condition if (!$value) ...
.
Assert::null ($value, ?string $description=null)
$value
doit être null
, donc $value === null
.
Assert::notNull ($value, ?string $description=null)
$value
ne doit pas être null
, donc $value !== null
.
Assert::nan ($value, ?string $description=null)
$value
doit être Not a Number. Utilisez uniquement le site Assert::nan()
pour les tests NAN. La
valeur NAN est très spécifique et les assertions Assert::same()
ou Assert::equal()
peuvent se
comporter de manière imprévisible.
Assert::count ($count, Countable|array $value, ?string $description=null)
Le nombre d'éléments dans $value
doit être $count
. Donc identique à
count($value) === $count
.
Assert::type (string|object $type, $value, ?string $description=null)
$value
doit être d'un type donné. Comme $type
nous pouvons utiliser une chaîne de
caractères :
array
list
– tableau indexé dans l'ordre croissant des clés numériques à partir de zéro.bool
callable
float
int
null
object
resource
scalar
string
- nom de la classe ou de l'objet directement, alors il faut passer
$value instanceof $type
Assert::exception (callable $callable, string $class, ?string $message=null, $code=null)
Lors de l'invocation de $callable
, une exception de l'instance $class
doit être levée. Si nous
passons $message
, le message de l'exception doit correspondre. Et si nous passons
$code
, le code de l'exception doit être le même.
Par exemple, ce test échoue car le message de l'exception ne correspond pas :
Assert::exception(
fn() => throw new App\InvalidValueException('Zero value'),
App\InvalidValueException::class,
'Value is to low',
);
Le site Assert::exception()
renvoie une exception levée, vous pouvez donc tester 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'invocation de $callable
génère les erreurs attendues (c'est-à-dire les avertissements, les avis,
etc.). Comme $type
nous spécifions une des constantes E_...
, par exemple E_WARNING
. Et si
on passe $message
, le message d'erreur doit également correspondre au modèle. Par
exemple :
Assert::error(
fn() => $i++,
E_NOTICE,
'Undefined variable: i',
);
Si le callback génère plus d'erreurs, nous devons les attendre toutes dans l'ordre exact. Dans ce cas, nous passons le
tableau à $type
:
Assert::error(function () {
$a++;
$b++;
}, [
[E_NOTICE, 'Undefined variable: a'],
[E_NOTICE, 'Undefined variable: b'],
]);
Si $type
est le nom de la classe, cette assertion se comporte de la même manière que
Assert::exception()
.
Assert::noError (callable $callable)
Vérifie que la fonction $callable
ne lève aucun avertissement/notice/erreur ou exception PHP. Elle est utile
pour tester un morceau de code où il n'y a pas d'autre assertion.
Assert::match (string $pattern, $actual, ?string $description=null)
$actual
doit correspondre à $pattern
. Nous pouvons utiliser deux variantes de motifs : les
expressions régulières ou les caractères génériques.
Si nous transmettons une expression régulière à $pattern
, nous devons utiliser ~
or #
pour la délimiter. Les autres délimiteurs ne sont pas pris en charge. Par exemple, test où $var
ne doit contenir
que des chiffres hexadécimaux :
Assert::match('#^[0-9a-f]$#i', $var);
L'autre variante est similaire à la comparaison de chaînes de caractères, mais nous pouvons utiliser certains caractères
génériques dans $pattern
:
%a%
un ou plusieurs caractères, à l'exception des caractères de fin de ligne%a?%
zéro ou plus de tout 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 plus de tout, y compris les caractères de fin de ligne%s%
un ou plusieurs caractères d'espace blanc, à l'exception des caractères de fin de ligne%s?%
zéro ou plusieurs caractères d'espace blanc, à l'exception des caractères de fin de ligne%S%
un ou plusieurs caractères sauf l'espace blanc%S?%
zéro ou plus de caractères sauf l'espace blanc%c%
un seul caractère de n'importe quelle sorte (sauf les caractères de fin de ligne)%d%
un ou plusieurs chiffres%d?%
zéro ou plusieurs chiffres%i%
valeur entière signée%f%
un nombre à virgule flottante%h%
un ou plusieurs chiffres HEX%w%
un ou plusieurs caractères alphanumériques%%
un caractère %.
Exemples :
# 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)
L'assertion est identique à Assert::match() mais le motif est chargé depuis
$file
. Elle est utile pour tester des chaînes très longues. Le fichier de test est lisible.
Assert::fail (string $message, $actual=null, $expected=null)
Cette assertion échoue toujours. Elle est simplement pratique. Nous pouvons optionnellement passer les valeurs attendues et réelles.
Attentes
Si nous voulons comparer des structures plus complexes avec 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 de hachage du mot de passe, mais nous savons qu'il doit être une chaîne
hexadécimale. Et la seule chose que nous savons de l'élément suivant est qu'il doit être un objet DateTime
.
Dans ces cas, nous pouvons utiliser le paramètre Tester\Expect
à l'intérieur du paramètre
$expected
des méthodes Assert::equal()
et Assert::notEqual()
, qui peuvent être utilisées
pour décrire facilement la structure.
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'));
Avec Expect
, nous pouvons faire presque les mêmes affirmations qu'avec Assert
. Nous avons donc des
méthodes comme Expect::same()
, Expect::match()
, Expect::count()
, etc. De plus, nous
pouvons les enchaîner comme suit :
Expect::type(MyIterator::class)->andCount(5); # we expect MyIterator and items count is 5
Ou bien, nous pouvons écrire nos propres gestionnaires d'assertions.
Expect::that(function ($value) {
# return false if expectation fails
});
Enquête sur les assertions échouées
Le testeur montre où se trouve l'erreur lorsqu'une assertion échoue. Lorsque nous comparons des structures complexes, le
testeur crée des dumps des valeurs comparées et les enregistre dans le répertoire output
. Par exemple, lorsque le
test imaginaire Arrays.recursive.phpt
échoue, les vidages seront enregistrés comme suit :
app/
└── tests/
├── output/
│ ├── Arrays.recursive.actual # actual value
│ └── Arrays.recursive.expected # expected value
│
└── Arrays.recursive.phpt # failing test
Nous pouvons changer le nom du répertoire par Tester\Dumper::$dumpDir
.