Qu’est-ce qu’atoum?¶
atoum est un framework de test unitaire, tout comme PHPUnit ou SimpleTest, mais il présente quelques avantages par rapport à ces derniers :
- Moderne, utilisant les innovations des dernières versions de PHP ;
- il est simple et facile à apprendre;
- il est intuitif, sa syntaxe se veut la plus proche du langage naturel anglais;
- malgré les évolutions constantes d’atoum, la rétrocompatibilité est une des priorités de ses développeurs.
Vous pouvez trouver plus d’information sur le site officiel.
Démarrer avec atoum¶
Vous devez d’abord l’installer, et puis essayez de démarrer votre premier test. Mais pour comprendre comment le faire, vous devez de garder à l’esprit de la philosophie d’atoum.
La philosophie d’atoum¶
Vous avez besoin d’écrire une classe de test pour chaque classe testée. Lorsque vous voulez tester une valeur, vous devez :
- indiquer le type de cette valeur (entier, décimal, tableau, chaîne de caractères, etc.);
- indiquer les contraintes devant s’appliquer à cette valeur (égal à, nulle, contenant quelque chose, etc.).
Extension¶
Atoum propose une série d’extension qui peuvent être utilisé. Pour les découvrir, il suffit d’aller sur le site dédié.
Installation¶
Si vous souhaitez utiliser atoum, il vous suffit de télécharger la dernière version.
Vous pouvez installer atoum de plusieurs manières :
- à l’aide de composer ;
- en téléchargeant l”archive PHAR ;
- en clonant le dépôt Github ;
- voir aussi l’integration d’atoum dans votre framework.
Composer¶
Composer est un outil de gestion de dépendance en PHP.
Assurez-vous que vous disposez d’une installation de composer fonctionnelle
Ajoutez atoum/atoum
à vos dépendances de développement :
composer require --dev atoum/atoum
Archive PHAR¶
Une archive PHAR (PHp ARchive) est créée automatiquement à chaque modification d’atoum.
PHAR est un format d’archive applicative pour PHP.
Installation¶
Vous pouvez télécharger la dernière version stable d’atoum directement depuis le site officiel : http://downloads.atoum.org/nightly/atoum.phar
Mise à jour¶
Pour mettre à jour le PHAR, utiliser simplement la commande :
$ php -d phar.readonly=0 atoum.phar --update
Note
Le processus de mise à jour modifie l’archive PHAR. Cependant, par défaut la configuration de PHP ne l’autorise pas. Voilà pourquoi il faut utiliser la directive -d phar.readonly=0
.
Si une version plus récente existe, elle sera alors téléchargée automatiquement et installée au sein de l’archive :
$ php -d phar.readonly=0 atoum.phar --update
Checking if a new version is available... Done !
Update to version 'nightly-2416-201402121146'... Done !
Enable version 'nightly-2416-201402121146'... Done !
Atoum was updated to version 'nightly-2416-201402121146' successfully !
S’il n’existe pas de version plus récente, atoum s’arrêtera immédiatement :
$ php -d phar.readonly=0 atoum.phar --update
Checking if a new version is available... Done !
There is no new version available !
atoum ne demande aucune confirmation de la part de l’utilisateur pour réaliser la mise à jour, car il est très facile de revenir à une version précédente.
Lister les versions contenues dans l’archive¶
Vous pouvez lister les versions disponibles dans les archives en utilisant --list-available-versions
ou -lav
:
$ php atoum.phar -lav
nightly-941-201201011548
nightly-1568-201210311708
* nightly-2416-201402121146
La liste des versions de l’archive est affichée. La version actuellement active est précédée par *
.
Changer la version courante¶
Pour activer une autre version, il suffit d’utiliser l’argument --enable-version
, ou -ev
en version abrégée, suivi du nom de la version à utiliser :
$ php -d phar.readonly=0 atoum.phar -ev DEVELOPMENT
Note
La modification de la version courante nécessite la modification de l’archive PHAR. Cependant, par défaut la configuration de PHP ne l’autorise pas. Voilà pourquoi il faut utiliser la directive -d phar.readonly=0
.
Suppression d’anciennes versions¶
Au cours du temps, l’archive peut contenir plusieurs versions d’atoum qui ne sont plus utilisées.
Pour les supprimer, il suffit d’utiliser l’argument --delete-version
, ou -dv
dans sa version abrégée, suivi du nom de la version à supprimer :
$ php -d phar.readonly=0 atoum.phar -dv nightly-941-201201011548
La version est alors supprimée.
Avertissement
Il n’est pas possible de supprimer la version active.
Note
La suppression d’une version nécessite la modification de l’archive PHAR. par défaut la configuration de PHP ne l’autorise pas.
Voilà pourquoi il faut utiliser la directive -d phar.readonly=0
.
Github¶
Si vous souhaitez utiliser atoum directement depuis ses sources, vous pouvez cloner ou « forker » le dépôt github : git://github.com/atoum/atoum.git
Premiers tests¶
Vous avez besoin d’écrire une classe de test pour chaque classe testé.
Imaginez que vous vouliez tester la traditionnelle classe HelloWorld
, alors vous devez créer la classe de test test\units\HelloWorld
.
Avertissement
Si vous débutez avec atoum, il est recommandé d’installer le paquet ´atoum-stubs <https://packagist.org/packages/atoum/stubs>´_. Celui-ci vous fournira de l’auto-complétion au sein de votre IDE.
Note
atoum utilise les espaces de noms. Par exemple, pour tester la classe Vendor\Project\HelloWorld
, vous devez créer la classe Vendor\Project\tests\units\HelloWorld
.
Voici le code de la classe HelloWorld
que nous allons tester.
<?php
# src/Vendor/Project/HelloWorld.php
namespace Vendor\Project;
class HelloWorld
{
public function getHiAtoum ()
{
return 'Hi atoum !';
}
}
Maintenant, voici le code de la classe de test que nous pourrions écrire.
<?php
# src/Vendor/Project/tests/units/HelloWorld.php
// La classe de test a son propre namespace :
// Le namespace de la classe à tester + "tests\units"
namespace Vendor\Project\tests\units;
// Vous devez inclure la classe testée (si vous n'avez pas d'autoloader)
require_once __DIR__ . '/../../HelloWorld.php';
use atoum;
/*
* Classe de test pour Vendor\Project\HelloWorld
*
* Remarquez qu'elle porte le même nom que la classe à tester
* et qu'elle dérive de la classe atoum
*/
class HelloWorld extends atoum
{
/*
* Cette méthode est dédiée à la méthode getHiAtoum()
*/
public function testGetHiAtoum ()
{
$this
// création d'une nouvelle instance de la classe à tester
->given($this->newTestedInstance)
->then
// nous testons que la méthode getHiAtoum retourne bien
// une chaîne de caractère...
->string($this->testedInstance->getHiAtoum())
// ... et que la chaîne est bien celle attendue,
// c'est-à-dire 'Hi atoum !'
->isEqualTo('Hi atoum !')
;
}
}
Maintenant, lançons nos tests. Vous devriez voir quelque chose comme ça :
$ ./vendor/bin/atoum -f src/Vendor/Project/tests/units/HelloWorld.php
> PHP path: /usr/bin/php
> PHP version:
=> PHP 5.6.3 (cli) (built: Nov 13 2014 18:31:57)
=> Copyright (c) 1997-2014 The PHP Group
=> Zend Engine v2.6.0, Copyright (c) 1998-2014 Zend Technologies
> Vendor\Project\tests\units\HelloWorld...
[S___________________________________________________________][1/1]
=> Test duration: 0.00 second.
=> Memory usage: 0.25 Mb.
> Total test duration: 0.00 second.
> Total test memory usage: 0.25 Mb.
> Running duration: 0.04 second.
Success (1 test, 1/1 method, 0 void method, 0 skipped method, 2 assertions)!
Nous venons de tester que la méthode getHiAtoum
:
- retourne une chaîne de caractère;
- que c’est égale à
"Hi atoum !"
.
Les tests sont passés, tout est au vert. Voilà, votre code est solide comme un roc grâce à atoum !
Dissection du test¶
Il est important que vous compreniez chaque chose que nous utilisons dans ce test. Regardons chaque partie.
Nous utilisons l’espace de noms Vendor\Project\tests\units
où Vendor\Project
est l’espace de noms de la classe et tests\units
la partie de l’espace de noms utiliser par atoum pour comprendre que nous sommes dans l’espace de nom de test. Cette espace de nom est configurable et ceci est expliqué dans la section appropriée.
Ensuite, à l’intérieur de la méthode testée, nous utilisons une synthaxe spécial given et then. Ils ne font rien d’autre que rendre le test plus lisible.
Finalement, nous utilisons un autre truc simple newTestedInstance et testedInstance pour obtenir une instance de la classe testée.
Lancement des tests¶
Exécutable¶
atoum dispose d’un exécutable qui vous permet de lancer vos tests en ligne de commande.
Avec l’archive phar¶
Si vous utiliser l’archive phar, elle est déjà exécutable.
linux / mac¶
$ php path/to/atoum.phar
windows¶
C:\> X:\Path\To\php.exe X:\Path\To\atoum.phar
Fichiers à exécuter¶
For specific files¶
Pour lancer les tests d’un fichier, il vous suffit d’utiliser l’option -f ou –files.
$ ./bin/atoum -f tests/units/MyTest.php
Pour un dossier¶
Pour lancer les tests d’un répertoire, il vous suffit d’utiliser l’option -d ou –directories.
$ ./bin/atoum -d tests/units
Vous trouverez d’autres arguments dans la section approprié lié à la ligne de commande.
Filtres¶
Une fois que vous avez préciser à atoum les fichiers à exécuter, vous pouvez filtrer ce qui sera réellement exécuter.
Par espace de noms¶
Pour filtrer sur les espace de nom, par example exécuter le test seulement sur un espace de nom, il suffit d’utiliser l’option -ns
or --namespaces
.
$ ./bin/atoum -d tests/units -ns mageekguy\\atoum\\tests\\units\\asserters
Note
Il est important de doubler chaque backslash pour éviter qu’ils soient interprétés par le shell.
Une classe ou une méthode¶
Pour filtrer sur une classe ou une méthode, c’est-à-dire exécuter seulement des tests d’une classe ou une méthode, il suffit d’utiliser l’option -m
ou --methods
.
$ ./bin/atoum -d tests/units -m mageekguy\\atoum\\tests\\units\\asserters\\string::testContains
Note
Il est important de doubler chaque backslash pour éviter qu’ils soient interprétés par le shell.
Vous pouvez remplacer le nom de la classe ou de la méthode par *
pour signifier tous
.
$ ./bin/atoum -d tests/units -m mageekguy\\atoum\\tests\\units\\asserters\\string::*
En utilisant « * » au lieu d’un nom de classe signifie que vous pouvez filtrer par nom de la méthode.
$ ./bin/atoum -d tests/units -m *::testContains
Tags¶
Tout comme de nombreux outils, dont Behat, atoum vous permet de taguer vos tests unitaires et de n’exécuter que ceux ayant un ou plusieurs tags spécifiques.
Pour cela, il faut commencer par définir un ou plusieurs tags pour une ou plusieurs classes de tests unitaires.
Cela se fait très simplement grâce aux annotations et à la balise @tags :
<?php
namespace vendor\project\tests\units;
require_once __DIR__ . '/atoum.phar';
use mageekguy\atoum;
/**
* @tags thisIsOneTag thisIsTwoTag thisIsThreeTag
*/
class foo extends atoum\test
{
public function testBar()
{
// ...
}
}
De la même manière, il est également possible de taguer les méthodes de test.
Note
Les tags définis au niveau d’une méthode prennent le pas sur ceux définis au niveau de la classe.
<?php
namespace vendor\project\tests\units;
require_once __DIR__ . '/atoum.phar';
use mageekguy\atoum;
class foo extends atoum\test
{
/**
* @tags thisIsOneMethodTag thisIsTwoMethodTag thisIsThreeMethodTag
*/
public function testBar()
{
// ...
}
}
Une fois les tags nécessaires définis, il n’y a plus qu’à exécuter les tests avec le ou les tags adéquates à l’aide de l’option --tags
, ou -t
dans sa version courte :
$ ./bin/atoum -d tests/units -t thisIsOneTag
Attention, cette instruction n’a de sens que s’il y a une ou plusieurs classes de tests unitaires et qu’au moins l’une d’entre elles porte le tag spécifié. Dans le cas contraire, aucun test ne sera exécuté.
Il est possible de définir plusieurs tags :
$ ./bin/atoum -d tests/units -t thisIsOneTag thisIsThreeTag
Dans ce dernier cas, les classes de tests ayant été tagués soit avec thisIsOneTag, soit avec thisIsThreeTag, seront les seules à être exécutées.
Comment écrire des scénarios de test¶
Après avoir créer votre premier test et compris comment le lancer<lancement-des-tests>, vous voulez probablement écrire de meilleurs tests. Dans cette section, vous trouverez comment ajouter du sucre syntaxique pour vous aider dans l’écriture de vos tests et ce de manière simple.
Il est possible d’écrire des tests unitaires avec atoum de plusieurs manières, et l’une d’elles est d’utiliser des mots-clefs tels que given
, if
, and
ou bien encore then
, when
ou assert
qui permettent de mieux organiser et de rendre plus lisibles les tests.
given
, if
, and
et then
¶
L’utilisation de ces mots-clefs est très intuitive :
<?php
$this
->given($computer = new computer())
->if($computer->prepare())
->and(
$computer->setFirstOperand(2),
$computer->setSecondOperand(2)
)
->then
->object($computer->add())
->isIdenticalTo($computer)
->integer($computer->getResult())
->isEqualTo(4)
;
Il est important de noter que ces mots-clés n’ont pas un autre but que de donner aux tests une forme plus lisible. Il ne serve aucun but technique. Le seul but est d’aider le lecteur, les humains ou plus précisément le développeur, à comprendre ce qui se passe dans le test.
Ainsi, given
, if
et and
permettent de définir les conditions préalables pour que les assertions qui suivent le mot-clef then
passent avec succès.
Cependant, il n’y a aucune règle ou grammaire qui régissent la syntaxe de l’ordre de ces mots-clés pour atoum.
Ainsi, le développeur utilisera ces mots-clés à bon escient pour rendre les tests aussi lisibles que possible. Cependant, si elle est utilisé de façon incorrecte, vous pourriez finir avec des tests comme suit :
<?php
$this
->and($computer = new computer())
->if($computer->setFirstOperand(2))
->then
->given($computer->setSecondOperand(2))
->object($computer->add())
->isIdenticalTo($computer)
->integer($computer->getResult())
->isEqualTo(4)
;
Pour les mêmes raisons, l’utilisation de then
est facultative.
Il est également important de noter qu’il est tout à fait possible d’écrire le même test en n’utilisant aucun mot-clef :
<?php
$computer = new computer();
$computer->setFirstOperand(2);
$computer->setSecondOperand(2);
$this
->object($computer->add())
->isIdenticalTo($computer)
->integer($computer->getResult())
->isEqualTo(4)
;
Le test ne sera pas plus lent ou plus rapide à exécuter, et il n’y a aucun avantage à utiliser une notation plutôt qu’une autre, l’important est d’en choisir une et de s’y tenir. De cette façon, cela permet de facilité la maintenance des tests (le problème est exactement le même que les conventions de codage).
when¶
En plus de given
, if
, and
et then
, il existe également d’autres mots-clefs.
L’un d’entre eux est when
. Il dispose d’une fonctionnalité spécifique introduite pour contourner le fait qu’il est illégal d’écrire en PHP le code suivant :
<?php # ignore
$this
->if($array = array(uniqid()))
->and(unset($array[0]))
->then
->sizeOf($array)
->isZero()
;
Le langage génère en effet dans ce cas l’erreur fatale : Parse error: syntax error, unexpected 'unset' (T_UNSET), expecting ')'
Il est en effet impossible d’utiliser unset()
comme argument d’une fonction.
Pour résoudre ce problème, le mot-clef when
est capable d’interpréter l’éventuelle fonction anonyme qui lui est passée en argument, ce qui permet d’écrire le test précédent de la manière suivante :
<?php
$this
->if($array = array(uniqid()))
->when(
function() use ($array) {
unset($array[0]);
}
)
->then
->sizeOf($array)
->isZero()
;
Bien évidemment, si when
ne reçoit pas de fonction anonyme en argument, il se comporte exactement comme given
, if
, and
et then
, à savoir qu’il ne fait absolument rien fonctionnellement parlant.
assert¶
Enfin, il existe le mot-clef assert
qui a également un fonctionnement un peu particulier.
Pour illustrer son fonctionnement, le test suivant va être utilisé :
<?php
$this
->given($foo = new \mock\foo())
->and($bar = new bar($foo))
->if($bar->doSomething())
->then
->mock($foo)
->call('doOtherThing')
->once()
->if($bar->setValue(uniqid()))
->then
->mock($foo)
->call('doOtherThing')
->exactly(2)
;
Le test précédent présente un inconvénient en terme de maintenance, car si le développeur a besoin d’intercaler un ou plusieurs nouveaux appels à bar::doOtherThing() entre les deux appels déjà effectués, il sera obligé de mettre à jour en conséquence la valeur de l’argument passé à exactly(). Pour remédier à ce problème, vous pouvez remettre à zéro un mock de 2 manières différentes :
- soit en utilisant $mock->getMockController()->resetCalls() ;
- soit en utilisant $this->resetMock($mock).
<?php
$this
->given($foo = new \mock\foo())
->and($bar = new bar($foo))
->if($bar->doSomething())
->then
->mock($foo)
->call('doOtherThing')
->once()
// 1ère manière
->given($foo->getMockController()->resetCalls())
->if($bar->setValue(uniqid()))
->then
->mock($foo)
->call('doOtherThing')
->once()
// 2ème manière
->given($this->resetMock($foo))
->if($bar->setValue(uniqid()))
->then
->mock($foo)
->call('doOtherThing')
->once()
;
Ces méthodes effacent la mémoire du contrôleur, il est donc possible d’écrire l’assertion suivante comme si le bouchon n’avait jamais été utilisé.
Le mot-clef assert
permet de se passer de l’appel explicite à resetCalls()
ou resetMock
et de plus il provoque l’effacement de la mémoire de l’ensemble des adaptateurs et des contrôleurs de mock définis au moment de son utilisation.
Grâce à lui, il est donc possible d’écrire le test précédent d’une façon plus simple et plus lisible, d’autant qu’il est possible de passer une chaîne de caractère à assert afin d’expliquer le rôle des assertions suivantes :
<?php
$this
->assert("Bar n'a pas de valeur")
->given($foo = new \mock\foo())
->and($bar = new bar($foo))
->if($bar->doSomething())
->then
->mock($foo)
->call('doOtherThing')
->once()
->assert('Bar a une valeur')
->if($bar->setValue(uniqid()))
->then
->mock($foo)
->call('doOtherThing')
->once()
;
La chaîne de caractères sera de plus reprise dans les messages générés par atoum si l’une des assertions ne passe pas avec succès.
newTestedInstance & testedInstance¶
Lorsque l’on effectue des tests, il faut bien souvent créer une nouvelle instance de la classe et passer celle-ci dans divers paramètres. Une aide à l’écriture est disponible pour ce cas précis, il s’agit de newTestedInstance
et de testedInstance
Voici un exemple :
namespace jubianchi\atoum\preview\tests\units;
use atoum;
use jubianchi\atoum\preview\foo as testedClass;
class foo extends atoum
{
public function testBar()
{
$this
->if($foo = new testedClass())
->then
->object($foo->bar())->isIdenticalTo($foo)
;
}
}
Ceci peut être simplifié avec la nouvelle syntaxe :
namespace jubianchi\atoum\preview\tests\units;
use atoum;
class foo extends atoum
{
public function testBar()
{
$this
->if($this->newTestedInstance)
->then
->object($this->testedInstance->bar())
->isTestedInstance()
;
}
}
Comme on le voit, c’est légèrement plus simple, mais surtout cela présente deux avantages :
- On ne manipule pas le nom de la classe testée
- On ne manipule pas l’instance ainsi créée
Par ailleurs, on peut facilement valider que l’on a bien l’instance testée avec isTestedInstance, comme expliqué dans l’exemple précédent.
Pour passer des arguments au constructeur, il suffit de le faire au travers de newTestedInstance
:
$this->newTestedInstance($argument1, $argument2);
Si vous voulez tester une méthode statique de votre classe, vous pouvez récupérer la classe testée avec cette syntaxe :
namespace jubianchi\atoum\preview\tests\units;
use atoum;
class foo extends atoum
{
public function testBar()
{
$this
->if($class = $this->testedClass->getClass())
->then
->object($class::bar())
;
}
}
Accès aux constantes de la classe testée¶
Si vous avez besoin d’accéder aux constantes de la classe testée, vous pouvez y accéder de deux façons :
<?php
namespace
{
class Foo
{
const A = 'a';
}
}
namespace tests\units
{
class Foo extends \atoum\test
{
public function testFoo()
{
$this
->given($this->newTestedInstance())
->then
->string($this->getTestedClassName()::A)->isEqualTo('a')
->string($this->testedInstance::A)->isEqualTo('a')
;
}
}
}
Avertissement
Vous avez besoin d’initialiser l’instance avec newTestedInstance
, pour avoir accès aux constantes.
testedClass¶
Comme testedInstance
, vous pouvez utiliser testedClass
pour écrire des tests plus compréhensible. testedClass
permet d’écrire des assertions dynamiques sur les classes testées :
<?php
$this
->testedClass
->hasConstant('FOO')
->isFinal()
;
Vous pouvez aller plus loin avec les assertions de classe.
Listes des asserters¶
Pour écrire des tests plus explicites et moins verbeux, atoum fourni plusieurs asserters qui donnent accès a des assertions spécifiques aux types testés.
atoum possède différents asserters spécialisés permettant de manipuler différents éléments, les assertes héritent d’autres qu’ils spécialisent. Ceci permettant d’aider à garder une consistance entre les différents asserters et force à utiliser les même noms d’assertion.
Voici l’arbre d’héritage des asserters :
-- asserter (abstract)
|-- error
|-- mock
|-- stream
|-- variable
| |-- array
| | `-- castToArray
| |-- boolean
| |-- class
| | `-- testedClass
| |-- integer
| | |-- float
| | `-- sizeOf
| |-- object
| | |-- dateInterval
| | |-- dateTime
| | | `-- mysqlDateTime
| | |-- exception
| | `-- iterator
| | `-- generator
| |-- resource
| `-- string
| |-- castToString
| |-- hash
| |-- output
| `-- utf8String
`-- function
Note
La syntaxe générale des asserters/assertions est :
$this->[asserter]($value)->[assertion];
Note
La plupart des assertions sont fluent, comme vous le verrez ci-dessous.
Note
A la fin du chapitre, vous trouverez plusieurs trucs & astuces relatif aux assertions et asserters, pensez à le lire!
afterDestructionOf¶
C’est l’assertion dédiée à la destruction des objets.
Cette assertion ne fait que prendre un objet, vérifier que la méthode __destruct()
est bien définie puis l’appelle.
Si __destruct()
existe bien et si son appel se passe sans erreur ni exception, alors le test passe.
<?php
$this
->afterDestructionOf($objectWithDestructor) // passe
->afterDestructionOf($objectWithoutDestructor) // échoue
;
array¶
C’est l’assertion dédiée aux tableaux.
Note
array
étant un mot réservé en PHP, il n’a pas été possible de créer une assertion array
. Elle s’appelle donc phpArray
et un alias array
a été créé. Vous pourrez donc rencontrer des ->phpArray()
ou des ->array()
.
Il est conseillé d’utiliser exclusivement ->array()
afin de simplifier la lecture des tests.
Sucre syntaxique¶
Il est à noter, qu’afin de simplifier l’écriture des tests sur les tableaux, du sucre syntaxique est disponible. Celui-ci permet d’effectuer diverses assertions directement sur les clefs du tableau testé.
$a = [
'foo' => 42,
'bar' => '1337'
];
$this
->array($a)
->integer['foo']->isEqualTo(42)
->string['bar']->isEqualTo('1337')
;
Note
This writing form is available from PHP 5.4.
child¶
Avec child
vous pouvez faire une assertion sur un sous tableau.
<?php
$array = array(
'ary' => array(
'key1' => 'abc',
'key2' => 123,
'key3' => array(),
),
);
$this
->array($array)
->child['ary'](function($child)
{
$child
->hasSize(3)
->hasKeys(array('key1', 'key2', 'key3'))
->contains(123)
->child['key3'](function($child)
{
$child->isEmpty;
});
});
Note
Cette forme d’écriture n’est disponible qu’à partir de PHP 5.4.
contains¶
contains
vérifie qu’un tableau contient une certaine donnée.
<?php
$fibonacci = array('1', 2, '3', 5, '8', 13, '21');
$this
->array($fibonacci)
->contains('1') // passe
->contains(1) // passe, ne vérifie pas...
->contains('2') // ... le type de la donnée
->contains(10) // échoue
;
Note
contains
ne fait pas de recherche récursive.
Avertissement
contains
ne teste pas le type de la donnée.containsValues¶
containsValues
vérifie qu’un tableau contient toutes les données fournies dans un tableau.
<?php
$fibonacci = array('1', 2, '3', 5, '8', 13, '21');
$this
->array($array)
->containsValues(array(1, 2, 3)) // passe
->containsValues(array('5', '8', '13')) // passe
->containsValues(array(0, 1, 2)) // échoue
;
Note
containsValues
ne fait pas de recherche récursive.
Avertissement
containsValues
ne teste pas le type des données.hasKey¶
hasKey
vérifie qu’un tableau contient une certaine clef.
<?php
$fibonacci = array('1', 2, '3', 5, '8', 13, '21');
$atoum = array(
'name' => 'atoum',
'owner' => 'mageekguy',
);
$this
->array($fibonacci)
->hasKey(0) // passe
->hasKey(1) // passe
->hasKey('1') // passe
->hasKey(10) // échoue
->array($atoum)
->hasKey('name') // passe
->hasKey('price') // échoue
;
Note
hasKey
ne fait pas de recherche récursive.
Avertissement
hasKey
ne teste pas le type des clefs.
hasKeys¶
hasKeys
vérifie qu’un tableau contient toutes les clefs fournies dans un tableau.
<?php
$fibonacci = array('1', 2, '3', 5, '8', 13, '21');
$atoum = array(
'name' => 'atoum',
'owner' => 'mageekguy',
);
$this
->array($fibonacci)
->hasKeys(array(0, 2, 4)) // passe
->hasKeys(array('0', 2)) // passe
->hasKeys(array('4', 0, 3)) // passe
->hasKeys(array(0, 3, 10)) // échoue
->array($atoum)
->hasKeys(array('name', 'owner')) // passe
->hasKeys(array('name', 'price')) // échoue
;
Note
hasKeys
ne fait pas de recherche récursive.
Avertissement
hasKey
ne teste pas le type des clefs.
hasSize¶
hasSize
vérifie la taille d’un tableau.
<?php
$fibonacci = array('1', 2, '3', 5, '8', 13, '21');
$this
->array($fibonacci)
->hasSize(7) // passe
->hasSize(10) // échoue
;
Note
hasSize
n’est pas récursif.
isEmpty¶
isEmpty
vérifie qu’un tableau est vide.
<?php
$emptyArray = array();
$nonEmptyArray = array(null, null);
$this
->array($emptyArray)
->isEmpty() // passe
->array($nonEmptyArray)
->isEmpty() // échoue
;
isEqualTo¶
Voir aussi
isEqualTo
est une méthode héritée de l’asserter variable
.
Pour plus d’informations, reportez-vous à la documentation de variable::isEqualTo
isIdenticalTo¶
Voir aussi
isIdenticalTo
est une méthode héritée de l’asserter variable
.
Pour plus d’informations, reportez-vous à la documentation de variable::isIdenticalTo
isNotEmpty¶
isNotEmpty
vérifie qu’un tableau n’est pas vide.
<?php
$emptyArray = array();
$nonEmptyArray = array(null, null);
$this
->array($emptyArray)
->isNotEmpty() // échoue
->array($nonEmptyArray)
->isNotEmpty() // passe
;
isNotEqualTo¶
Voir aussi
isNotEqualTo
est une méthode héritée de l’asserter variable
.
Pour plus d’informations, reportez-vous à la documentation de variable::isNotEqualTo
isNotIdenticalTo¶
Voir aussi
isNotIdenticalTo
est une méthode héritée de l’asserter variable
.
Pour plus d’informations, reportez-vous à la documentation de variable::isNotIdenticalTo
keys¶
keys
vous permet de récupérer un asserter de type array contenant les clefs du tableau testé.
<?php
$atoum = array(
'name' => 'atoum',
'owner' => 'mageekguy',
);
$this
->array($atoum)
->keys
->isEqualTo(
array(
'name',
'owner',
)
)
;
notContains¶
notContains
vérifie qu’un tableau ne contient pas une donnée.
<?php
$fibonacci = array('1', 2, '3', 5, '8', 13, '21');
$this
->array($fibonacci)
->notContains(null) // passe
->notContains(1) // échoue
->notContains(10) // passe
;
Note
notContains
ne fait pas de recherche récursive.
Avertissement
contains
ne teste pas le type de la donnée.notContainsValues¶
notContainsValues
vérifie qu’un tableau ne contient aucune des données fournies dans un tableau.
<?php
$fibonacci = array('1', 2, '3', 5, '8', 13, '21');
$this
->array($array)
->notContainsValues(array(1, 4, 10)) // échoue
->notContainsValues(array(4, 10, 34)) // passe
->notContainsValues(array(1, '2', 3)) // échoue
;
Note
notContainsValues
ne fait pas de recherche récursive.
Avertissement
notContainsValues
ne teste pas le type des données.notHasKey¶
notHasKey
vérifie qu’un tableau ne contient pas une certaine clef.
<?php
$fibonacci = array('1', 2, '3', 5, '8', 13, '21');
$atoum = array(
'name' => 'atoum',
'owner' => 'mageekguy',
);
$this
->array($fibonacci)
->notHasKey(0) // échoue
->notHasKey(1) // échoue
->notHasKey('1') // échoue
->notHasKey(10) // passe
->array($atoum)
->notHasKey('name') // échoue
->notHasKey('price') // passe
;
Note
notHasKey
ne fait pas de recherche récursive.
Avertissement
notHasKey
ne teste pas le type des clefs.
notHasKeys¶
notHasKeys
vérifie qu’un tableau ne contient aucune des clefs fournies dans un tableau.
<?php
$fibonacci = array('1', 2, '3', 5, '8', 13, '21');
$atoum = array(
'name' => 'atoum',
'owner' => 'mageekguy',
);
$this
->array($fibonacci)
->notHasKeys(array(0, 2, 4)) // échoue
->notHasKeys(array('0', 2)) // échoue
->notHasKeys(array('4', 0, 3)) // échoue
->notHasKeys(array(10, 11, 12)) // passe
->array($atoum)
->notHasKeys(array('name', 'owner')) // échoue
->notHasKeys(array('foo', 'price')) // passe
;
Note
notHasKeys
ne fait pas de recherche récursive.
Avertissement
notHasKey
ne teste pas le type des clefs.
size¶
size
vous permet de récupérer un asserter de type integer contenant la taille du tableau testé.
<?php
$fibonacci = array('1', 2, '3', 5, '8', 13, '21');
$this
->array($fibonacci)
->size
->isGreaterThan(5)
;
strictlyContains¶
strictlyContains
vérifie qu’un tableau contient une certaine donnée (même valeur et même type).
<?php
$fibonacci = array('1', 2, '3', 5, '8', 13, '21');
$this
->array($fibonacci)
->strictlyContains('1') // passe
->strictlyContains(1) // échoue
->strictlyContains('2') // échoue
->strictlyContains(2) // passe
->strictlyContains(10) // échoue
;
Note
strictlyContains
ne fait pas de recherche récursive.
Avertissement
strictlyContains
teste le type de la donnée.strictlyContainsValues¶
strictlyContainsValues
vérifie qu’un tableau contient toutes les données fournies dans un tableau (même valeur et même type).
<?php
$fibonacci = array('1', 2, '3', 5, '8', 13, '21');
$this
->array($array)
->strictlyContainsValues(array('1', 2, '3')) // passe
->strictlyContainsValues(array(1, 2, 3)) // échoue
->strictlyContainsValues(array(5, '8', 13)) // passe
->strictlyContainsValues(array('5', '8', '13')) // échoue
->strictlyContainsValues(array(0, '1', 2)) // échoue
;
Note
strictlyContainsValues
ne fait pas de recherche récursive.
Avertissement
strictlyContainsValues
teste le type des données.strictlyNotContains¶
strictlyNotContains
vérifie qu’un tableau ne contient pas une donnée (même valeur et même type).
<?php
$fibonacci = array('1', 2, '3', 5, '8', 13, '21');
$this
->array($fibonacci)
->strictlyNotContains(null) // passe
->strictlyNotContains('1') // échoue
->strictlyNotContains(1) // passe
->strictlyNotContains(10) // passe
;
Note
strictlyNotContains
ne fait pas de recherche récursive.
Avertissement
strictlyNotContains
teste le type de la donnée.strictlyNotContainsValues¶
strictlyNotContainsValues
vérifie qu’un tableau ne contient aucune des données fournies dans un tableau (même valeur et même type).
<?php
$fibonacci = array('1', 2, '3', 5, '8', 13, '21');
$this
->array($array)
->strictlyNotContainsValues(array('1', 4, 10)) // échoue
->strictlyNotContainsValues(array(1, 4, 10)) // passe
->strictlyNotContainsValues(array(4, 10, 34)) // passe
->strictlyNotContainsValues(array('1', 2, '3')) // échoue
->strictlyNotContainsValues(array(1, '2', 3)) // passe
;
Note
strictlyNotContainsValues
ne fait pas de recherche récursive.
Avertissement
strictlyNotContainsValues
teste le type des données.values¶
keys
vous permet de récupérer un asserter de type array contenant les clefs du tableau testé.
Exemple :
<?php
$this
->given($arr = [0 => 'foo', 2 => 'bar', 3 => 'baz'])
->then
->array($arr)->values
->string[0]->isEqualTo('foo')
->string[1]->isEqualTo('bar')
->string[2]->isEqualTo('baz')
;
Nouveau dans la version 2.9.0: assertion values ajouté
boolean¶
C’est l’assertion dédiée aux booléens.
Si vous essayez de tester une variable qui n’est pas un booléen avec cette assertion, cela échouera.
Note
null
n’est pas un booléen. Reportez-vous au manuel de PHP pour savoir ce que is_bool considère ou non comme un booléen.
isEqualTo¶
Voir aussi
isEqualTo
est une méthode héritée de l’asserter variable
.
Pour plus d’informations, reportez-vous à la documentation de variable::isEqualTo
isFalse¶
isFalse
vérifie que le booléen est strictement égal à false
.
<?php
$true = true;
$false = false;
$this
->boolean($true)
->isFalse() // échoue
->boolean($false)
->isFalse() // passe
;
isIdenticalTo¶
Voir aussi
isIdenticalTo
est une méthode héritée de l’asserter variable
.
Pour plus d’informations, reportez-vous à la documentation de variable::isIdenticalTo
isNotEqualTo¶
Voir aussi
isNotEqualTo
est une méthode héritée de l’asserter variable
.
Pour plus d’informations, reportez-vous à la documentation de variable::isNotEqualTo
isNotIdenticalTo¶
Voir aussi
isNotIdenticalTo
est une méthode héritée de l’asserter variable
.
Pour plus d’informations, reportez-vous à la documentation de variable::isNotIdenticalTo
isTrue¶
isTrue
vérifie que le booléen est strictement égal à true
.
<?php
$true = true;
$false = false;
$this
->boolean($true)
->isTrue() // passe
->boolean($false)
->isTrue() // échoue
;
castToArray¶
C’est l’assertion dédiée aux tests sur le transtypage d’objets en tableaux.
<?php
class AtoumVersions {
private $versions = ['1.0', '2.0', '2.1'];
public function __toArray() {
return $this->versions;
}
}
$this
->castToArray(new AtoumVersions())
->contains('1.0')
;
Voir aussi
L’asserter castToArray
retourne une instance de l’asserter array
.
Vous pouvez donc utiliser toutes les assertions de l’asserter array
castToString¶
C’est l’assertion dédiée aux tests sur le transtypage d’objets en chaîne de caractères.
<?php
class AtoumVersion {
private $version = '1.0';
public function __toString() {
return 'atoum v' . $this->version;
}
}
$this
->castToString(new AtoumVersion())
->isEqualTo('atoum v1.0')
;
contains¶
Voir aussi
contains
est une méthode héritée de l’asserter string
.
Pour plus d’informations, reportez-vous à la documentation de string::contains
notContains¶
Voir aussi
notContains
est une méthode héritée de l’asserter string
.
Pour plus d’informations, reportez-vous à la documentation de string::notContains
hasLength¶
Voir aussi
hasLength
est une méthode héritée de l’asserter string
.
Pour plus d’informations, reportez-vous à la documentation de string::hasLength
hasLengthGreaterThan¶
Voir aussi
hasLengthGreaterThan
est une méthode héritée de l’asserter string
.
Pour plus d’informations, reportez-vous à la documentation de string::hasLengthGreaterThan
hasLengthLessThan¶
Voir aussi
hasLengthLessThan
est une méthode héritée de l’asserter string
.
Pour plus d’informations, reportez-vous à la documentation de string::hasLengthLessThan
isEmpty¶
Voir aussi
isEmpty
est une méthode héritée de l’asserter string
.
Pour plus d’informations, reportez-vous à la documentation de string::isEmpty
isEqualTo¶
Voir aussi
isEqualTo
est une méthode héritée de l’asserter variable
.
Pour plus d’informations, reportez-vous à la documentation de variable::isEqualTo
isEqualToContentsOfFile¶
Voir aussi
isEqualToContentsOfFile
est une méthode héritée de l’asserter string
.
Pour plus d’informations, reportez-vous à la documentation de string::isEqualToContentsOfFile
isIdenticalTo¶
Voir aussi
isIdenticalTo
est une méthode héritée de l’asserter variable
.
Pour plus d’informations, reportez-vous à la documentation de variable::isIdenticalTo
isNotEmpty¶
Voir aussi
isNotEmpty
est une méthode héritée de l’asserter string
.
Pour plus d’informations, reportez-vous à la documentation de string::isNotEmpty
isNotEqualTo¶
Voir aussi
isNotEqualTo
est une méthode héritée de l’asserter variable
.
Pour plus d’informations, reportez-vous à la documentation de variable::isNotEqualTo
isNotIdenticalTo¶
Voir aussi
isNotIdenticalTo
est une méthode héritée de l’asserter variable
.
Pour plus d’informations, reportez-vous à la documentation de variable::isNotIdenticalTo
matches¶
Voir aussi
matches
est une méthode héritée de l’asserter string
.
Pour plus d’informations, reportez-vous à la documentation de string::matches
class¶
C’est l’assertion dédiée aux classes.
<?php
$object = new \StdClass;
$this
->class(get_class($object))
->class('\StdClass')
;
Note
Le mot-clef class
étant réservé en PHP, il n’a pas été possible de créer une assertion class
. Elle s’appelle donc phpClass
et un alias class
a été créé. Vous pourrez donc rencontrer des ->phpClass()
ou des ->class()
.
Il est conseillé d’utiliser exclusivement ->class()
.
hasConstant¶
hasConstant
vérifie que la classe possède bien la constante testée.
<?php
$this
->class('\StdClass')
->hasConstant('FOO') // échoue
->class('\FilesystemIterator')
->hasConstant('CURRENT_AS_PATHNAME') // passe
;
hasInterface¶
hasInterface
vérifie que la classe implémente une interface donnée.
<?php
$this
->class('\ArrayIterator')
->hasInterface('Countable') // passe
->class('\StdClass')
->hasInterface('Countable') // échoue
;
hasMethod¶
hasMethod
vérifie que la classe contient une méthode donnée.
<?php
$this
->class('\ArrayIterator')
->hasMethod('count') // passe
->class('\StdClass')
->hasMethod('count') // échoue
;
hasNoParent¶
hasNoParent
vérifie que la classe n’hérite d’aucune classe.
<?php
$this
->class('\StdClass')
->hasNoParent() // passe
->class('\FilesystemIterator')
->hasNoParent() // échoue
;
Avertissement
hasNoParent
ne vérifie pas les interfaces, uniquement les classes héritées.hasParent¶
hasParent
vérifie que la classe hérite bien d’une classe.
<?php
$this
->class('\StdClass')
->hasParent() // échoue
->class('\FilesystemIterator')
->hasParent() // passe
;
Avertissement
hasParent
ne vérifie pas les interfaces, uniquement les classes héritées.isAbstract¶
isAbstract
vérifie que la classe est abstraite.
<?php
$this
->class('\StdClass')
->isAbstract() // échoue
;
isFinal¶
isFinal
vérifie que la classe est finale.
Dans le cas suivant, nous testons une classe non final (StdClass
) :
<?php
$this
->class('\StdClass')
->isFinal() // échoue
;
Dans le cas suivant, la classe testée est une classe final
<?php
$this
->testedClass
->isFinal() // passe
;
$this
->testedClass
->isFinal // passe aussi
;
isSubclassOf¶
isSubclassOf
vérifie que la classe hérite de la classe donnée.
<?php
$this
->class('\FilesystemIterator')
->isSubclassOf('\DirectoryIterator') // passe
->isSubclassOf('\SplFileInfo') // passe
->isSubclassOf('\StdClass') // échoue
;
dateInterval¶
C’est l’assertion dédiée à l’objet DateInterval.
Si vous essayez de tester une variable qui n’est pas un objet DateInterval
(ou une classe qui l’étend) avec cette assertion, cela échouera.
isCloneOf¶
Voir aussi
isCloneOf
est une méthode héritée de l’asserter object
.
Pour plus d’informations, reportez-vous à la documentation de object::isCloneOf
isEqualTo¶
isEqualTo
vérifie que la durée de l’objet DateInterval
est égale à la durée d’un autre objet DateInterval
.
<?php
$di = new DateInterval('P1D');
$this
->dateInterval($di)
->isEqualTo( // passe
new DateInterval('P1D')
)
->isEqualTo( // échoue
new DateInterval('P2D')
)
;
isGreaterThan¶
isGreaterThan
vérifie que la durée de l’objet DateInterval
est supérieure à la durée d’un autre objet DateInterval
.
<?php
$di = new DateInterval('P2D');
$this
->dateInterval($di)
->isGreaterThan( // passe
new DateInterval('P1D')
)
->isGreaterThan( // échoue
new DateInterval('P2D')
)
;
isGreaterThanOrEqualTo¶
isGreaterThanOrEqualTo
vérifie que la durée de l’objet DateInterval
est supérieure ou égale à la durée d’un autre objet DateInterval
.
<?php
$di = new DateInterval('P2D');
$this
->dateInterval($di)
->isGreaterThanOrEqualTo( // passe
new DateInterval('P1D')
)
->isGreaterThanOrEqualTo( // passe
new DateInterval('P2D')
)
->isGreaterThanOrEqualTo( // échoue
new DateInterval('P3D')
)
;
isIdenticalTo¶
Voir aussi
isIdenticalTo
est une méthode héritée de l’asserter object
.
Pour plus d’informations, reportez-vous à la documentation de object::isIdenticalTo
isInstanceOf¶
Voir aussi
isInstanceOf
est une méthode héritée de l’asserter object
.
Pour plus d’informations, reportez-vous à la documentation de object::isInstanceOf
isLessThan¶
isLessThan
vérifie que la durée de l’objet DateInterval
est inférieure à la durée d’un autre objet DateInterval
.
<?php
$di = new DateInterval('P1D');
$this
->dateInterval($di)
->isLessThan( // passe
new DateInterval('P2D')
)
->isLessThan( // échoue
new DateInterval('P1D')
)
;
isLessThanOrEqualTo¶
isLessThanOrEqualTo
vérifie que la durée de l’objet DateInterval
est inférieure ou égale à la durée d’un autre objet DateInterval
.
<?php
$di = new DateInterval('P2D');
$this
->dateInterval($di)
->isLessThanOrEqualTo( // passe
new DateInterval('P3D')
)
->isLessThanOrEqualTo( // passe
new DateInterval('P2D')
)
->isLessThanOrEqualTo( // échoue
new DateInterval('P1D')
)
;
isNotEqualTo¶
Voir aussi
isNotEqualTo
est une méthode héritée de l’asserter object
.
Pour plus d’informations, reportez-vous à la documentation de object::isNotEqualTo
isNotIdenticalTo¶
Voir aussi
isNotIdenticalTo
est une méthode héritée de l’asserter object
.
Pour plus d’informations, reportez-vous à la documentation de object::isNotIdenticalTo
isZero¶
isZero
vérifie que la durée de l’objet DateInterval
est égale à 0.
<?php
$di1 = new DateInterval('P0D');
$di2 = new DateInterval('P1D');
$this
->dateInterval($di1)
->isZero() // passe
->dateInterval($di2)
->isZero() // échoue
;
dateTime¶
C’est l’assertion dédiée à l’objet DateTime.
Si vous essayez de tester une variable qui n’est pas un objet DateTime
(ou une classe qui l’étend) avec cette assertion, cela échouera.
hasDate¶
hasDate
vérifie la partie date de l’objet DateTime
.
<?php
$dt = new DateTime('1981-02-13');
$this
->dateTime($dt)
->hasDate('1981', '02', '13') // passe
->hasDate('1981', '2', '13') // passe
->hasDate(1981, 2, 13) // passe
;
hasDateAndTime¶
hasDateAndTime
vérifie la partie date et heure de l’objet DateTime
.
<?php
$dt = new DateTime('1981-02-13 01:02:03');
$this
->dateTime($dt)
// passe
->hasDateAndTime('1981', '02', '13', '01', '02', '03')
// passe
->hasDateAndTime('1981', '2', '13', '1', '2', '3')
// passe
->hasDateAndTime(1981, 2, 13, 1, 2, 3)
;
hasDay¶
hasDay
vérifie le jour de l’objet DateTime
.
<?php
$dt = new DateTime('1981-02-13');
$this
->dateTime($dt)
->hasDay(13) // passe
;
hasHours¶
hasHours
vérifie l’heure de l’objet DateTime
.
<?php
$dt = new DateTime('01:02:03');
$this
->dateTime($dt)
->hasHours('01') // passe
->hasHours('1') // passe
->hasHours(1) // passe
;
hasMinutes¶
hasMinutes
vérifie les minutes de l’objet DateTime
.
<?php
$dt = new DateTime('01:02:03');
$this
->dateTime($dt)
->hasMinutes('02') // passe
->hasMinutes('2') // passe
->hasMinutes(2) // passe
;
hasMonth¶
hasMonth
vérifie le mois de l’objet DateTime
.
<?php
$dt = new DateTime('1981-02-13');
$this
->dateTime($dt)
->hasMonth(2) // passe
;
hasSeconds¶
hasSeconds
vérifie les secondes de l’objet DateTime
.
<?php
$dt = new DateTime('01:02:03');
$this
->dateTime($dt)
->hasSeconds('03') // passe
->hasSeconds('3') // passe
->hasSeconds(3) // passe
;
hasTime¶
hasTime
vérifie le temps de l’objet DateTime
.
<?php
$dt = new DateTime('01:02:03');
$this
->dateTime($dt)
->hasTime('01', '02', '03') // passe
->hasTime('1', '2', '3') // passe
->hasTime(1, 2, 3) // passe
;
hasTimezone¶
hasTimezone
vérifie le fuseau horaire de l’objet DateTime
.
<?php
$dt = new DateTime();
$this
->dateTime($dt)
->hasTimezone('Europe/Paris')
;
hasYear¶
hasYear
vérifie l’année de l’objet DateTime
.
<?php
$dt = new DateTime('1981-02-13');
$this
->dateTime($dt)
->hasYear(1981) // passe
;
isCloneOf¶
Voir aussi
isCloneOf
est une méthode héritée de l’asserter object
.
Pour plus d’informations, reportez-vous à la documentation de object::isCloneOf
isEqualTo¶
Voir aussi
isEqualTo
est une méthode héritée de l’asserter object
.
Pour plus d’informations, reportez-vous à la documentation de object::isEqualTo
isIdenticalTo¶
Voir aussi
isIdenticalTo
est une méthode héritée de l’asserter object
.
Pour plus d’informations, reportez-vous à la documentation de object::isIdenticalTo
isImmutable¶
isImmutable
vérifie que qu’un objet DateTime
est immuable.
<?php
$dt = new DateTime('1981-02-13');
$this
->dateTime($dt)
->isImmutable(1981) // rate
;
$dt = new DateTimeImmutable('1981-02-13');
$this
->dateTime($dt)
->isImmutable(1981) // réussit
;
isInstanceOf¶
Voir aussi
isInstanceOf
est une méthode héritée de l’asserter object
.
Pour plus d’informations, reportez-vous à la documentation de object::isInstanceOf
isNotEqualTo¶
Voir aussi
isNotEqualTo
est une méthode héritée de l’asserter object
.
Pour plus d’informations, reportez-vous à la documentation de object::isNotEqualTo
isNotIdenticalTo¶
Voir aussi
isNotIdenticalTo
est une méthode héritée de l’asserter object
.
Pour plus d’informations, reportez-vous à la documentation de object::isNotIdenticalTo
error¶
C’est l’assertion dédiée aux erreurs.
<?php
$this
->when(
function() {
trigger_error('message');
}
)
->error()
->exists() // or notExists
;
Note
La syntaxe utilise les fonctions anonymes (aussi appelées fermetures ou closures) introduites en PHP 5.3. Pour plus de précision, lisez la documentation PHP sur les fonctions anonymes.
Avertissement
Les types d’erreur E_ERROR, E_PARSE, E_CORE_ERROR, E_CORE_WARNING, E_COMPILE_ERROR, E_COMPILE_WARNING ainsi que la plupart des E_STRICT ne peuvent pas être gérés avec cette fonction.
exists¶
exists
vérifie qu’une erreur a été levée lors de l’exécution du code précédent.
<?php
$this
->when(
function() {
trigger_error('message');
}
)
->error()
->exists() // pass
->when(
function() {
// code without error
}
)
->error()
->exists() // failed
;
notExists¶
notExists
vérifie qu’aucune erreur n’a été levée lors de l’exécution du code précédent.
<?php
$this
->when(
function() {
trigger_error('message');
}
)
->error()
->notExists() // fails
->when(
function() {
// code without error
}
)
->error()
->notExists() // pass
;
withType¶
withType
vérifie le type de l’erreur levée.
<?php
$this
->when(
function() {
trigger_error('message');
}
)
->error()
->withType(E_USER_NOTICE) // pass
->exists()
->when(
function() {
trigger_error('message');
}
)
->error()
->withType(E_USER_WARNING) // failed
->exists()
;
withAnyType¶
withAnyType
ne vérifie pas le type de l’erreur. C’est le comportement par défaut de l’asserter. Donc ->error()->withAnyType()->exists()
est l’équivalent de ->error()->exists()
. Cette méthode existe pour ajouter de la sémantique dans vos tests.
<?php
$this
->when(
function() {
trigger_error('message');
}
)
->error()
->withAnyType() // pass
->exists()
->when(
function() {
}
)
->error()
->withAnyType()
->exists() // fails
;
withMessage¶
withMessage
vérifie le contenu du message de l’erreur levée.
<?php
$this
->when(
function() {
trigger_error('message');
}
)
->error()
->withMessage('message')
->exists() // passes
;
$this
->when(
function() {
trigger_error('message');
}
)
->error()
->withMessage('MESSAGE')
->exists() // fails
;
withAnyMessage¶
withAnyMessage
ne vérifie pas le message de l’erreur. C’est le comportement par défaut de l’asserter. Donc ->error()->withAnyMessage()->exists()
est l’équivalent de ->error()->exists()
. Cette méthode existe pour ajouter de la sémantique dans vos tests.
<?php
$this
->when(
function() {
trigger_error();
}
)
->error()
->withAnyMessage()
->exists() // passes
;
$this
->when(
function() {
trigger_error('message');
}
)
->error()
->withAnyMessage()
->exists() // passes
;
$this
->when(
function() {
}
)
->error()
->withAnyMessage()
->exists() // fails
;
withPattern¶
withPattern
vérifie le contenu du message de l’erreur soulevée par l’expression régulière.
<?php
$this
->when(
function() {
trigger_error('message');
}
)
->error()
->withPattern('/^mess.*$/')
->exists() // passes
;
$this
->when(
function() {
trigger_error('message');
}
)
->error()
->withPattern('/^mess$/')
->exists() // fails
;
exception¶
C’est l’assertion dédiée aux exceptions.
<?php
$this
->exception(
function() use($myObject) {
// ce code lève une exception: throw new \Exception;
$myObject->doOneThing('wrongParameter');
}
)
;
Note
La syntaxe utilise les fonctions anonymes (aussi appelées fermetures ou closures) introduites en PHP 5.3. Pour plus de précision, lisez la documentation PHP sur les fonctions anonymes.
Nous pouvons même facilement récupérer la dernière exception via $this->exception
.
<?php
$this
->exception(
function() use($myObject) {
// ce code lève une exception: throw new \Exception('erreur', 42);
$myObject->doOneThing('wrongParameter');
}
)->isIdenticalTo($this->exception) // passes
;
$this->exception->hasCode(42); // passes
$this->exception->hasMessage('erreur'); // passes
Note
Avant atoum 3.0.0, si vous avez besoin d’effectuer des assertions, vous aviez besoin d’ajouter atoum\test $test
en argument de la closure. Après la version 3.0.0, vous pouvez simplement utiliser $this à l’intérieur de la closure, afin d’effectuer des assertions.
hasCode¶
hasCode
vérifie le code de l’exception.
<?php
$this
->exception(
function() use($myObject) {
// ce code lève une exception: throw new \Exception('erreur', 42);
$myObject->doOneThing('wrongParameter');
}
)
->hasCode(42)
;
hasDefaultCode¶
hasDefaultCode
vérifie que le code de l’exception est la valeur par défaut, c’est-à-dire 0.
<?php
$this
->exception(
function() use($myObject) {
// ce code lève une exception: throw new \Exception;
$myObject->doOneThing('wrongParameter');
}
)
->hasDefaultCode()
;
Note
hasDefaultCode
is equivalent to hasCode(0)
.
hasMessage¶
hasMessage
vérifie le message de l’exception.
<?php
$this
->exception(
function() use($myObject) {
// ce code lève une exception: throw new \Exception('Message');
$myObject->doOneThing('wrongParameter');
}
)
->hasMessage('Message') // passes
->hasMessage('message') // fails
;
hasNestedException¶
hasNestedException
vérifie que l’exception contient une référence vers l’exception précédente. Si le type d’exception est fournie, cela va aussi vérifier la classe de l’exception.
<?php
$this
->exception(
function() use($myObject) {
// ce code lève une exception: throw new \Exception('Message');
$myObject->doOneThing('wrongParameter');
}
)
->hasNestedException() // fails
->exception(
function() use($myObject) {
try {
// ce code lève une exception: throw new \FirstException('Message 1', 42);
$myObject->doOneThing('wrongParameter');
}
// ... l'exception est attrapée...
catch(\FirstException $e) {
// ... puis relancée, encapsulée dans une seconde exception
throw new \SecondException('Message 2', 24, $e);
}
}
)
->isInstanceOf('\FirstException') // fails
->isInstanceOf('\SecondException') // passes
->hasNestedException() // passes
->hasNestedException(new \FirstException) // passes
->hasNestedException(new \SecondException) // fails
;
isCloneOf¶
Voir aussi
isCloneOf
est une méthode héritée de l’asserter object
.
Pour plus d’informations, reportez-vous à la documentation de object::isCloneOf
isEqualTo¶
Voir aussi
isEqualTo
est une méthode héritée de l’asserter object
.
Pour plus d’informations, reportez-vous à la documentation de object::isEqualTo
isIdenticalTo¶
Voir aussi
isIdenticalTo
est une méthode héritée de l’asserter object
.
Pour plus d’informations, reportez-vous à la documentation de object::isIdenticalTo
isInstanceOf¶
Voir aussi
isInstanceOf
est une méthode héritée de l’asserter object
.
Pour plus d’informations, reportez-vous à la documentation de object::isInstanceOf
isNotEqualTo¶
Voir aussi
isNotEqualTo
est une méthode héritée de l’asserter object
.
Pour plus d’informations, reportez-vous à la documentation de object::isNotEqualTo
isNotIdenticalTo¶
Voir aussi
isNotIdenticalTo
est une méthode héritée de l’asserter object
.
Pour plus d’informations, reportez-vous à la documentation de object::isNotIdenticalTo
extension¶
C’est l’assertion dédiée aux extensions PHP.
isLoaded¶
Vérifie si l’extension est chargée (installée et activée).
<?php
$this
->extension('json')
->isLoaded()
;
Note
Si vous avez besoin de lancer un test uniquement si une extension est présente, vous pouvez utiliser l’annotation PHP.
float¶
C’est l’assertion dédiée aux nombres décimaux.
Si vous essayez de tester une variable qui n’est pas un nombre décimal avec cette assertion, cela échouera.
Note
null
n’est pas un nombre décimal. Reportez-vous au manuel de PHP pour savoir ce que is_float considère ou non comme un nombre décimal.
isEqualTo¶
Voir aussi
isEqualTo
est une méthode héritée de l’asserter variable
.
Pour plus d’informations, reportez-vous à la documentation de variable::isEqualTo
isGreaterThan¶
Voir aussi
isGreaterThan
est une méthode héritée de l’asserter integer
.
Pour plus d’informations, reportez-vous à la documentation de integer::isGreaterThan
isGreaterThanOrEqualTo¶
Voir aussi
isGreaterThanOrEqualTo
est une méthode héritée de l’asserter integer
.
Pour plus d’informations, reportez-vous à la documentation de integer::isGreaterThanOrEqualTo
isIdenticalTo¶
Voir aussi
isIdenticalTo
est une méthode héritée de l’asserter variable
.
Pour plus d’informations, reportez-vous à la documentation de variable::isIdenticalTo
isLessThan¶
Voir aussi
isLessThan
est une méthode héritée de l’asserter integer
.
Pour plus d’informations, reportez-vous à la documentation de integer::isLessThan
isLessThanOrEqualTo¶
Voir aussi
isLessThanOrEqualTo
est une méthode héritée de l’asserter integer
.
Pour plus d’informations, reportez-vous à la documentation de integer::isLessThanOrEqualoo
isNearlyEqualTo¶
isNearlyEqualTo
vérifie que le nombre décimal est approximativement égal à la valeur qu’elle reçoit en argument.
En effet, en informatique, les nombres décimaux sont gérées d’une façon qui ne permet pas d’effectuer des comparaisons précises sans recourir à des outils spécialisés. Essayez par exemple d’exécuter la commande suivante :
$ php -r 'var_dump(1 - 0.97 === 0.03);'
bool(false)
Le résultat devrait pourtant être true
.
Note
Pour avoir plus d’informations sur ce phénomène, lisez la documentation PHP sur le type float et sa précision.
Cette méthode cherche donc à minorer ce problème.
<?php
$float = 1 - 0.97;
$this
->float($float)
->isNearlyEqualTo(0.03) // passe
->isEqualTo(0.03) // échoue
;
Note
Pour avoir plus d’informations sur l’algorithme utilisé, consultez le floating point guide.
isNotEqualTo¶
Voir aussi
isNotEqualTo
est une méthode héritée de l’asserter variable
.
Pour plus d’informations, reportez-vous à la documentation de variable::isNotEqualTo
isNotIdenticalTo¶
Voir aussi
isNotIdenticalTo
est une méthode héritée de l’asserter variable
.
Pour plus d’informations, reportez-vous à la documentation de variable::isNotIdenticalTo
isZero¶
Voir aussi
isZero
est une méthode héritée de l’asserter integer
.
Pour plus d’informations, reportez-vous à la documentation de integer::isZero
function¶
C’est l’asserter dédié aux fonctions natives qui sont mockée.
wasCalled¶
wasCalled
vérifie que la fonction mockée a été appelée.
wasCalledWithArguments¶
wasCalledWithArguments
permet de vérifier les arguments utilisé avec l’appel de la fonction.
wasCalledWithIdenticalArguments¶
wasCalledWithIdenticalArguments
permet de vérifier tous les arguments utilisé avec l’appel de la fonction.
wasCalledWithoutAnyArgument¶
wasCalledWithoutAnyArgument
vérifie que l’appel a la fonction a été effectué sans aucun argument.
Compter les appels¶
Si vous voulez vous pouvez effectuer une assertion supplémentaire en comptant le nombre d’appel à la fonction.
<?php
$this->function->error_log = true;
$this
->if($this->newTestedInstance())
->and($this->testedInstance->methodWithAnErrorLog($notExcepted = uniqid()))
->then
->function('error_log')
->wasCalledWithArguments('Value ' . $notExcepted . ' is not excepted here')
->once();
Ici, nous vérifions que notre fonction a été appelée une seule fois, avec les arguments fournis.
after¶
after
vérifie que la fonction a été appelée après la méthode passée en paramètre.
Voir aussi
after
a le même comportement que celui existant sur l’asserter des mock
.
Pour plus d’informations, reportez-vous à la documentation de mock::after
atLeastOnce¶
atLeastOnce
vérifie que la fonction a été appelée au moins une fois.
Voir aussi
atLeastOnce
a le même comportement que celui de l’asserter des mock
.
Pour plus d’informations, reportez-vous à la documentation de mock::atLeastOnce
before¶
after
vérifie que la fonction a été appelée avant la méthode passée en paramètre.
Voir aussi
before
is the same as the one on the mock
asserter.
For more information, refer to the documentation of mock::before
exactly¶
exactly
check that the mocked function has been called a specific number of times.
Voir aussi
exactly
is the same as the one on the mock
asserter.
For more information, refer to the documentation of mock::exactly
never¶
never
check that the mocked function has never been called.
Voir aussi
never
is the same as the one on the mock
asserter.
For more information, refer to the documentation of mock::never
once/twice/thrice¶
This asserters check that the mocked function has been called exactly:
- une fois (once)
- deux fois (twice)
- trois fois (thrice)
Voir aussi
once
is the same as the one on the mock
asserter.
For more information, refer to the documentation of mock::once/twice/thrice
generator¶
Il s’agit de l’asserter dédié aux generators.
L’asserter generator hérite l’asserter iterator
, vous pouvez donc utiliser toutes les assertions de celui-ci.
Exemple :
<?php
$generator = function() {
for ($i=0; $i<3; $i++) {
yield ($i+1);
}
};
$this
->generator($generator())
->hasSize(3)
;
Dans cet exemple, nous créons un générateur qui générera 3 valeurs, et nous vérifierons que la taille de ce qui est généré est de 3.
yields¶
yields
est utilisé pour facilité les tests sur les valeurs générée par le générateur.
Chaque fois que ->yields
est appelé, la valeur suivante du générateur est récupérée.
Vous pouvez ensuite utiliser tout les asserter sur cette valeur (par exemple class
, string
ou variable
).
Exemple :
<?php
$generator = function() {
for ($i=0; $i<3; $i++) {
yield ($i+1);
}
};
$this
->generator($generator())
->yields->variable->isEqualTo(1)
->yields->variable->isEqualTo(2)
->yields->integer->isEqualTo(3)
;
Dans cette exemple nous créer un générateur qui produit 3 valeurs : 1, 2 et 3.
Ensuite nous produisons chaque valeurs et effectuons une assertion sur celle-ci pour vérifier le type et la valeur.
Dans les deux premières valeurs produite, nous utilisons l’asserter variable
et nous ne vérifions que la valeur.
Avec la troisième valeur produite, nous vérifions qu’il s’agit bien d’un entier (toute asserter peut-être utiliser sur cette valeur) avant de vérifier la valeur.
returns¶
Note
Cette assertion ne fonctionne que avec PHP >= 7.0.
Depuis la version 7.0 de PHP, les générateurs peuvent retourner une valeur via un appel à la méthode ->getReturn()
.
Lorsque vous appeler ->returns
sur le l’asserter generator, atoum va renvoyé la valeur via la méthode ->getReturn()``sur l'asserter.
Ensuite vous pourrez utiliser n'importe quel autre asserter sur cette valeur comme avec l'assertion ``yields
.
Exemple :
<?php
$generator = function() {
for ($i=0; $i<3; $i++) {
yield ($i+1);
}
return 42;
};
$this
->generator($generator())
->yields->variable->isEqualTo(1)
->yields->variable->isEqualTo(2)
->yields->integer->isEqualTo(3)
->returns->integer->isEqualTo(42)
;
Dans cet exemple, nous effectuons quelques vérifications sur toutes les valeurs produites. On vérifie ensuite que le générateur renvoie un entier avec une valeur de 42 (tout comme un appel à l’assertion yields, vous pouvez utiliser n’importe quel asserter pour vérifier la valeur retournée).
Nouveau dans la version 3.0.0: Asserter generator ajouté
hash¶
C’est l’assertion dédiée aux tests sur les hashs (empreintes numériques).
contains¶
Voir aussi
contains
est une méthode héritée de l’asserter string
.
Pour plus d’informations, reportez-vous à la documentation de string::contains
isEqualTo¶
Voir aussi
isEqualTo
est une méthode héritée de l’asserter variable
.
Pour plus d’informations, reportez-vous à la documentation de variable::isEqualTo
isEqualToContentsOfFile¶
Voir aussi
isEqualToContentsOfFile
est une méthode héritée de l’asserter string
.
Pour plus d’informations, reportez-vous à la documentation de string::isEqualToContentsOfFile
isIdenticalTo¶
Voir aussi
isIdenticalTo
est une méthode héritée de l’asserter variable
.
Pour plus d’informations, reportez-vous à la documentation de variable::isIdenticalTo
isMd5¶
isMd5
vérifie que la chaîne de caractère est du format md5
, par exemple une chaîne de caractère d’une longueur de 32.
<?php
$hash = hash('md5', 'atoum');
$notHash = 'atoum';
$this
->hash($hash)
->isMd5() // passe
->hash($notHash)
->isMd5() // échoue
;
isNotEqualTo¶
Voir aussi
isNotEqualTo
est une méthode héritée de l’asserter variable
.
Pour plus d’informations, reportez-vous à la documentation de variable::isNotEqualTo
isNotIdenticalTo¶
Voir aussi
isNotIdenticalTo
est une méthode héritée de l’asserter variable
.
Pour plus d’informations, reportez-vous à la documentation de variable::isNotIdenticalTo
isSha1¶
isSha1
vérifie que la chaîne de caractère est du format sha1
, par exemple une chaîne de caractère d’une longueur de 40.
<?php
$hash = hash('sha1', 'atoum');
$notHash = 'atoum';
$this
->hash($hash)
->isSha1() // passe
->hash($notHash)
->isSha1() // échoue
;
isSha256¶
isSha256
vérifie que la chaîne de caractère est du format sha256
, par exemple une chaîne de caractère d’une longueur de 64 caractères.
<?php
$hash = hash('sha256', 'atoum');
$notHash = 'atoum';
$this
->hash($hash)
->isSha256() // passe
->hash($notHash)
->isSha256() // échoue
;
isSha512¶
isSha512
vérifie que la chaîne de caractère est du format sha512
, c’est-à-dire, une chaîne de caractère d’une longueur de 128 caractères.
<?php
$hash = hash('sha512', 'atoum');
$notHash = 'atoum';
$this
->hash($hash)
->isSha512() // passe
->hash($notHash)
->isSha512() // échoue
;
notContains¶
Voir aussi
notContains
est une méthode héritée de l’asserter string
.
Pour plus d’informations, reportez-vous à la documentation de string::notContains
integer¶
C’est l’assertion dédiée aux entiers.
Si vous essayez de tester une variable qui n’est pas un entier avec cette assertion, cela échouera.
Note
null
n’est pas un entier. Reportez-vous au manuel de PHP pour savoir ce que is_int considère ou non comme un entier.
isEqualTo¶
Voir aussi
isEqualTo
est une méthode héritée de l’asserter variable
.
Pour plus d’informations, reportez-vous à la documentation de variable::isEqualTo
isGreaterThan¶
isGreaterThan
vérifie que l’entier est strictement supérieur à une certaine donnée.
<?php
$zero = 0;
$this
->integer($zero)
->isGreaterThan(-1) // passe
->isGreaterThan('-1') // échoue car "-1"
// n'est pas un entier
->isGreaterThan(0) // échoue
;
isGreaterThanOrEqualTo¶
isGreaterThanOrEqualTo
vérifie que l’entier est supérieur ou égal à une certaine donnée.
<?php
$zero = 0;
$this
->integer($zero)
->isGreaterThanOrEqualTo(-1) // passe
->isGreaterThanOrEqualTo(0) // passe
->isGreaterThanOrEqualTo('-1') // échoue, car "-1"
// n'est pas un entier
;
isIdenticalTo¶
Voir aussi
isIdenticalTo
est une méthode héritée de l’asserter variable
.
Pour plus d’informations, reportez-vous à la documentation de variable::isIdenticalTo
isLessThan¶
isLessThan
vérifie que l’entier est strictement inférieur à une certaine donnée.
<?php
$zero = 0;
$this
->integer($zero)
->isLessThan(10) // passe
->isLessThan('10') // échoue, car "10" n'est pas un entier
->isLessThan(0) // échoue
;
isLessThanOrEqualTo¶
isLessThanOrEqualTo
vérifie que l’entier est inférieur ou égal à une certaine donnée.
<?php
$zero = 0;
$this
->integer($zero)
->isLessThanOrEqualTo(10) // passe
->isLessThanOrEqualTo(0) // passe
->isLessThanOrEqualTo('10') // échoue car "10"
// n'est pas un entier
;
isNotEqualTo¶
Voir aussi
isNotEqualTo
est une méthode héritée de l’asserter variable
.
Pour plus d’informations, reportez-vous à la documentation de variable::isNotEqualTo
isNotIdenticalTo¶
Voir aussi
isNotIdenticalTo
est une méthode héritée de l’asserter variable
.
Pour plus d’informations, reportez-vous à la documentation de variable::isNotIdenticalTo
isZero¶
isZero
vérifie que l’entier est égal à 0.
<?php
$zero = 0;
$notZero = -1;
$this
->integer($zero)
->isZero() // passe
->integer($notZero)
->isZero() // échoue
;
Note
isZero
est équivalent à isEqualTo(0)
.
mock¶
C’est l’assertion dédiée aux mocks.
<?php
$mock = new \mock\MyClass;
$this
->mock($mock)
;
Note
Reportez-vous à la documentation sur les bouchons (mock) pour obtenir plus d’informations sur la façon de créer et gérer les bouchons.
call¶
call
permet de spécifier une méthode du mock à tester, son appel doit être suivi d’un appel à une méthode de vérification d’appel comme atLeastOnce, once/twice/thrice, exactly, etc…
<?php
$this
->given($mock = new \mock\MyFirstClass)
->and($object = new MySecondClass($mock))
->if($object->methodThatCallMyMethod()) // Cela va appeler la méthode myMethod de $mock
->then
->mock($mock)
->call('myMethod')
->once()
;
after¶
after
vérifie que la méthode a été appelée après la méthode passée en paramètre.
<?php
$this
->when($mock = new \mock\example)
->if(
$mock->test2(),
$mock->test()
)
->mock($mock)
->call('test')
->after($this->mock($mock)->call('test2')->once())
->once() // passe
;
$this
->when($mock = new \mock\example)
->if(
$mock->test(),
$mock->test2()
)
->mock($mock)
->call('test')
->after($this->mock($mock)->call('test2')->once())
->once() // échoue
;
atLeastOnce¶
atLeastOnce
vérifie que la méthode testée (voir call) du mock testé a été appelée au moins une fois.
<?php
$mock = new \mock\MyFirstClass;
$this
->object(new MySecondClass($mock))
->mock($mock)
->call('myMethod')
->atLeastOnce()
;
before¶
before
vérifie que la méthode a été appelée avant la méthode passée en paramètre.
<?php
$this
->when($mock = new \mock\example)
->if(
$mock->test(),
$mock->test2()
)
->mock($mock)
->call('test')
->before($this->mock($mock)->call('test2')->once())
->once() // passe
;
$this
->when($mock = new \mock\example)
->if(
$mock->test2(),
$mock->test()
)
->mock($mock)
->call('test')
->before($this->mock($mock)->call('test2')->once())
->once() // échoue
;
exactly¶
exactly
vérifie que la méthode testée (voir call) du mock testé exactement un certain nombre de fois.
<?php
$mock = new \mock\MyFirstClass;
$this
->object(new MySecondClass($mock))
->mock($mock)
->call('myMethod')
->exactly(2)
;
Note
il existe une version simplifiée avec ->{2}
.
never¶
never
vérifie que la méthode testée (voir call) du mock testé n’a jamais été appelée.
<?php
$mock = new \mock\MyFirstClass;
$this
->object(new MySecondClass($mock))
->mock($mock)
->call('myMethod')
->never()
;
Note
never
est équivalent à exactly(0).
once/twice/thrice¶
Ces assertions vérifient que la méthode testée (voir call) du mock testé a été appelée exactement :
- une fois (once)
- deux fois (twice)
- trois fois (thrice)
<?php
$mock = new \mock\MyFirstClass;
$this
->object(new MySecondClass($mock))
->mock($mock)
->call('myMethod')
->once()
->call('mySecondMethod')
->twice()
->call('myThirdMethod')
->thrice()
;
Note
once
, twice
et thrice
sont respectivement équivalents à un appel à exactly(1), exactly(2) et exactly(3).
withAnyArguments¶
withAnyArguments
permet de ne pas spécifier les arguments attendus lors de l’appel à la méthode testée (voir call) du mock testé.
Cette méthode est surtout utile pour remettre à zéro les arguments, comme dans l’exemple suivant :
<?php
$mock = new \mock\MyFirstClass;
$this
->object(new MySecondClass($mock))
->mock($mock)
->call('myMethod')
->withArguments('first') ->once()
->withArguments('second') ->once()
->withAnyArguments()->exactly(2)
;
withArguments¶
withArguments
permet de spécifier les paramètres attendus lors de l’appel à la méthode testée (voir call) du mock testé.
<?php
$mock = new \mock\MyFirstClass;
$this
->object(new MySecondClass($mock))
->mock($mock)
->call('myMethod')
->withArguments('first', 'second')->once()
;
Avertissement
withArguments
ne teste pas le type des arguments.withIdenticalArguments¶
withIdenticalArguments
permet de spécifier les paramètres attendus lors de l’appel à la méthode testée (voir call) du mock testé.
<?php
$mock = new \mock\MyFirstClass;
$this
->object(new MySecondClass($mock))
->mock($mock)
->call('myMethod')
->withIdenticalArguments('first', 'second')->once()
;
Avertissement
withIdenticalArguments
teste le type des arguments.withAtLeastArguments¶
withAtLeastArguments
permet de spécifier les paramètres minimums attendus lors de l’appel à la méthode testée (voir call) du mock testé.
<?php
$this
->if($mock = new \mock\example)
->and($mock->test('a', 'b'))
->mock($mock)
->call('test')
->withAtLeastArguments(array('a'))->once() //passes
->withAtLeastArguments(array('a', 'b'))->once() //passes
->withAtLeastArguments(array('c'))->once() //fails
;
Avertissement
withAtLeastArguments
ne teste pas le type des arguments.withAtLeastIdenticalArguments¶
withAtLeastIdenticalArguments
permet de spécifier les paramètres minimums attendus lors de l’appel à la méthode testée (voir call) du mock testé.
<?php
$this
->if($mock = new \mock\example)
->and($mock->test(1, 2))
->mock($mock)
->call('test')
->withAtLeastIdenticalArguments(array(1))->once() //passes
->withAtLeastIdenticalArguments(array(1, 2))->once() //passes
->withAtLeastIdenticalArguments(array('1'))->once() //fails
;
Avertissement
withAtLeastIdenticalArguments
teste le type des arguments.withoutAnyArgument¶
withoutAnyArgument
permet de spécifier que la méthode ne doit recevoir aucun paramètre lors de son appel (voir call).
<?php
$this
->when($mock = new \mock\example)
->if($mock->test())
->mock($mock)
->call('test')
->withoutAnyArgument()->once() // passe
->if($mock->test2('argument'))
->mock($mock)
->call('test2')
->withoutAnyArgument()->once() // échoue
;
Note
withoutAnyArgument
reviens à appeler withAtLeastArguments avec un tableau vide : ->withAtLeastArguments(array())
.
receive¶
Est un alias de call.
<?php
$this
->given(
$connection = new mock\connection
)
->if(
$this->newTestedInstance($connection)
)
->then
->object($this->testedInstance->noMoreValue())->isTestedInstance
->mock($connection)->receive('newPacket')->withArguments(new packet)->once;
// Identique à
$this->mock($connection)->call('newPacket')->withArguments(new packet)->once;
wasCalled¶
wasCalled
vérifie qu’au moins une méthode du mock a été appelée au moins une fois.
<?php
$mock = new \mock\MyFirstClass;
$this
->object(new MySecondClass($mock))
->mock($mock)
->wasCalled()
;
wasNotCalled¶
wasNotCalled
vérifie qu’aucune méthode du mock n’a été appelée.
<?php
$mock = new \mock\MyFirstClass;
$this
->object(new MySecondClass($mock))
->mock($mock)
->wasNotCalled()
;
mysqlDateTime¶
C’est l’assertion dédiée aux objets décrivant une date MySQL et basée sur l’objet DateTime.
Les dates doivent utiliser un format compatible avec MySQL et de nombreux autre SGBD (Système de gestion de base de données)), à savoir « Y-m-d H:i:s » « Y-m-d H:i:s »
Note
Reportez-vous à la documentation de la fonction date() du manuel de PHP pour plus d’information.
Si vous essayez de tester une variable qui n’est pas un objet DateTime
(ou une classe qui l’étend) avec cette assertion, cela échouera.
hasDate¶
Voir aussi
hasDate
est une méthode héritée de l’asserter dateTime
.
Pour plus d’informations, reportez-vous à la documentation de dateTime::hasDate
hasDateAndTime¶
Voir aussi
hasDateAndTime
est une méthode héritée de l’asserter dateTime
.
Pour plus d’informations, reportez-vous à la documentation de dateTime::hasDateAndTime
hasDay¶
Voir aussi
hasDay
est une méthode héritée de l’asserter dateTime
.
Pour plus d’informations, reportez-vous à la documentation de dateTime::hasDay
hasHours¶
Voir aussi
hasHours
est une méthode héritée de l’asserter dateTime
.
Pour plus d’informations, reportez-vous à la documentation de dateTime::hasHours
hasMinutes¶
Indication
hasMinutes
est une méthode héritée de l’asserter dateTime
.
Pour plus d’informations, reportez-vous à la documentation de dateTime::hasMinutes
hasMonth¶
Voir aussi
hasMonth
est une méthode héritée de l’asserter dateTime
.
Pour plus d’informations, reportez-vous à la documentation de dateTime::hasMonth
hasSeconds¶
Voir aussi
hasSeconds
est une méthode héritée de l’asserter dateTime
.
Pour plus d’informations, reportez-vous à la documentation de dateTime::hasSeconds
hasTime¶
Voir aussi
hasTime
est une méthode héritée de l’asserter dateTime
.
Pour plus d’informations, reportez-vous à la documentation de dateTime::hasTime
hasTimezone¶
Voir aussi
hasTimezone
est une méthode héritée de l’asserter dateTime
.
Pour plus d’informations, reportez-vous à la documentation de dateTime::hasTimezone
hasYear¶
Voir aussi
hasYear
est une méthode héritée de l’asserter dateTime
.
Pour plus d’informations, reportez-vous à la documentation de dateTime::hasYear
isCloneOf¶
Voir aussi
isCloneOf
est une méthode héritée de l’asserter object
.
Pour plus d’informations, reportez-vous à la documentation de object::isCloneOf
isEqualTo¶
Voir aussi
isEqualTo
est une méthode héritée de l’asserter object
.
Pour plus d’informations, reportez-vous à la documentation de object::isEqualTo
isIdenticalTo¶
Voir aussi
isIdenticalTo
est une méthode héritée de l’asserter object
.
Pour plus d’informations, reportez-vous à la documentation de object::isIdenticalTo
isInstanceOf¶
Indication
isInstanceOf
est une méthode héritée de l’asserter object
.
Pour plus d’informations, reportez-vous à la documentation de object::isInstanceOf
isNotEqualTo¶
Voir aussi
isNotEqualTo
est une méthode héritée de l’asserter object
.
Pour plus d’informations, reportez-vous à la documentation de object::isNotEqualTo
isNotIdenticalTo¶
Voir aussi
isNotIdenticalTo
est une méthode héritée de l’asserter object
.
Pour plus d’informations, reportez-vous à la documentation de object::isNotIdenticalTo
object¶
C’est l’assertion dédiée aux objets.
Si vous essayez de tester une variable qui n’est pas un objet avec cette assertion, cela échouera.
Note
null
n’est pas un objet. Reportez-vous au manuel de PHP pour savoir ce que is_object considère ou non comme un objet.
hasSize¶
hasSize
vérifie la taille d’un objet qui implémente l’interface Countable
.
<?php
$countableObject = new GlobIterator('*');
$this
->object($countableObject)
->hasSize(3)
;
isCallable¶
<?php
class foo
{
public function __invoke()
{
// code
}
}
$this
->object(new foo)
->isCallable() // passe
->object(new StdClass)
->isCallable() // échoue
;
Note
Pour être identifiés comme callable
, vos objets devront être instanciés à partir de classes qui implémentent la méthode magique __invoke.
Voir aussi
isCallable
est une méthode héritée de l’asserter variable
.
Pour plus d’informations, reportez-vous à la documentation de variable::isCallable
isCloneOf¶
isCloneOf
vérifie qu’un objet est le clone d’un objet donné, c’est-à-dire que les objets sont égaux, mais ne pointent pas vers la même instance.
<?php
$object1 = new \StdClass;
$object2 = new \StdClass;
$object3 = clone($object1);
$object4 = new \StdClass;
$object4->foo = 'bar';
$this
->object($object1)
->isCloneOf($object2) // passe
->isCloneOf($object3) // passe
->isCloneOf($object4) // échoue
;
Note
Pour plus de précision, lisez la documentation PHP sur la comparaison d’objet.
isEmpty¶
isEmpty
vérifie que la taille d’un objet implémentant l’interface Countable
est égale à 0.
<?php
$countableObject = new GlobIterator('atoum.php');
$this
->object($countableObject)
->isEmpty()
;
Note
isEmpty
est équivalent à hasSize(0)
.
isEqualTo¶
isEqualTo
vérifie qu’un objet est égal à un autre.
Deux objets sont considérés égaux lorsqu’ils ont les mêmes attributs et valeurs, et qu’ils sont des instances de la même classe.
Note
Pour plus de précision, lisez la documentation PHP sur la comparaison d’objet.
Voir aussi
isEqualTo
est une méthode héritée de l’asserter variable
.
Pour plus d’informations, reportez-vous à la documentation de variable::isEqualTo
isIdenticalTo¶
isIdenticalTo
vérifie que deux objets sont identiques.
Deux objets sont considérés identiques lorsqu’ils font référence à la même instance de la même classe.
Note
Pour plus de précision, lisez la documentation PHP sur la comparaison d’objet.
Voir aussi
isIdenticalTo
est une méthode héritée de l’asserter variable
.
Pour plus d’informations, reportez-vous à la documentation de variable::isIdenticalTo
isInstanceOf¶
isInstanceOf
vérifie qu’un objet est :
- une instance de la classe donnée,
- une sous-classe de la classe donnée (abstraite ou non),
- une instance d’une classe qui implémente l’interface donnée.
<?php
$object = new \StdClass();
$this
->object($object)
->isInstanceOf('\StdClass') // passe
->isInstanceOf('\Iterator') // échoue
;
interface FooInterface
{
public function foo();
}
class FooClass implements FooInterface
{
public function foo()
{
echo "foo";
}
}
class BarClass extends FooClass
{
}
$foo = new FooClass;
$bar = new BarClass;
$this
->object($foo)
->isInstanceOf('\FooClass') // passe
->isInstanceOf('\FooInterface') // passe
->isInstanceOf('\BarClass') // échoue
->isInstanceOf('\StdClass') // échoue
->object($bar)
->isInstanceOf('\FooClass') // passe
->isInstanceOf('\FooInterface') // passe
->isInstanceOf('\BarClass') // passe
->isInstanceOf('\StdClass') // échoue
;
Note
Les noms des classes et des interfaces doivent être absolus, car les éventuelles importations d’espace de nommage ne sont pas prises en compte.
Indication
Notez qu’avec PHP >= 5.5
vous pouvez utiliser le mot-clé class
pour obtenir les noms de classe absolus, par exemple $this->object($foo)->isInstanceOf(FooClass::class)
.
isInstanceOfTestedClass¶
<?php
$this->newTestedInstance;
$object = new TestedClass();
$this->object($this->testedInstance)->isInstanceOfTestedClass;
$this->object($object)->isInstanceOfTestedClass;
isNotCallable¶
<?php
class foo
{
public function __invoke()
{
// code
}
}
$this
->variable(new foo)
->isNotCallable() // échoue
->variable(new StdClass)
->isNotCallable() // passe
;
Voir aussi
isNotCallable
est une méthode héritée de l’asserter variable
.
Pour plus d’informations, reportez-vous à la documentation de variable::isNotCallable
isNotEqualTo¶
isEqualTo
vérifie qu’un objet n’est pas égal à un autre.
Deux objets sont considérés égaux lorsqu’ils ont les mêmes attributs et valeurs, et qu’ils sont des instances de la même classe.
Note
Pour plus de précision, lisez la documentation PHP sur la comparaison d’objet.
Voir aussi
isNotEqualTo
est une méthode héritée de l’asserter variable
.
Pour plus d’informations, reportez-vous à la documentation de variable::isNotEqualTo
isNotIdenticalTo¶
isIdenticalTo
vérifie que deux objets ne sont pas identiques.
Deux objets sont considérés identiques lorsqu’ils font référence à la même instance de la même classe.
Note
Pour plus de précision, lisez la documentation PHP sur la comparaison d’objet.
Voir aussi
isNotIdenticalTo
est une méthode héritée de l’asserter variable
.
Pour plus d’informations, reportez-vous à la documentation de variable::isNotIdenticalTo
isNotInstanceOf¶
isNotInstanceOf
vérifie qu’un objet n’est pas :
- une instance de la classe donnée,
- une sous-classe de la classe donnée (abstraite ou non),
- une instance d’une classe qui implémente l’interface donnée.
<?php
$object = new \StdClass();
$this
->object($object)
->isNotInstanceOf('\StdClass') // échoue
->isNotInstanceOf('\Iterator') // échoue
;
Note
Tout comme isInstanceOf, le nom de la classe ou de l’interface doivent être absolus car les imports de namespace seront ignorés.
isNotTestedInstance¶
<?php
$this->newTestedInstance;
$this->object($this->testedInstance)->isNotTestedInstance; // fail
isTestedInstance¶
<?php
$this->newTestedInstance;
$this->object($this->testedInstance)->isTestedInstance;
$object = new TestedClass();
$this->object($object)->isTestedInstance; // échec
output¶
C’est l’assertion dédiée aux tests sur les sorties, c’est-à-dire tout ce qui est censé être affiché à l’écran.
<?php
$this
->output(
function() {
echo 'Hello world';
}
)
;
Note
La syntaxe utilise les fonctions anonymes (aussi appelées fermetures ou closures) introduites en PHP 5.3. Pour plus de précision, lisez la documentation PHP sur les fonctions anonymes.
contains¶
Voir aussi
contains
est une méthode héritée de l’asserter string
.
Pour plus d’informations, reportez-vous à la documentation de string::contains
hasLength¶
Voir aussi
hasLength
est une méthode héritée de l’asserter string
.
Pour plus d’informations, reportez-vous à la documentation de string::hasLength
hasLengthGreaterThan¶
Voir aussi
hasLengthGreaterThan
est une méthode héritée de l’asserter string
.
Pour plus d’informations, reportez-vous à la documentation de string::hasLengthGreaterThan
hasLengthLessThan¶
Voir aussi
hasLengthLessThan
est une méthode héritée de l’asserter string
.
Pour plus d’informations, reportez-vous à la documentation de string::hasLengthLessThan
isEmpty¶
Voir aussi
isEmpty
est une méthode héritée de l’asserter string
.
Pour plus d’informations, reportez-vous à la documentation de string::isEmpty
isEqualTo¶
Voir aussi
isEqualTo
est une méthode héritée de l’asserter variable
.
Pour plus d’informations, reportez-vous à la documentation de variable::isEqualTo
isEqualToContentsOfFile¶
Voir aussi
isEqualToContentsOfFile
est une méthode héritée de l’asserter string
.
Pour plus d’informations, reportez-vous à la documentation de string::isEqualToContentsOfFile
isIdenticalTo¶
Voir aussi
isIdenticalTo
est une méthode héritée de l’asserter variable
.
Pour plus d’informations, reportez-vous à la documentation de variable::isIdenticalTo
isNotEmpty¶
Voir aussi
isNotEmpty
est une méthode héritée de l’asserter string
.
Pour plus d’informations, reportez-vous à la documentation de string::isNotEmpty
isNotEqualTo¶
Voir aussi
isNotEqualTo
est une méthode héritée de l’asserter variable
.
Pour plus d’informations, reportez-vous à la documentation de variable::isNotEqualTo
isNotIdenticalTo¶
Voir aussi
isNotIdenticalTo
est une méthode héritée de l’asserter variable
.
Pour plus d’informations, reportez-vous à la documentation de variable::isNotIdenticalTo
matches¶
Voir aussi
matches
est une méthode héritée de l’asserter string
.
Pour plus d’informations, reportez-vous à la documentation de string::matches
notContains¶
Voir aussi
notContains
est une méthode héritée de l’asserter string
.
Pour plus d’informations, reportez-vous à la documentation de string::notContains
resource¶
C’est l’assertion dédié au ´ressource <http://php.net/language.types.resource>´_.
isOfType¶
Cette méthode permet de comparer le type de ressource avec le type de la valeur fournie en paramètre. Dans l’exemple suivant, on vérifie que le paramètre est un stream.
$this
->resource($variable)
->isOfType('stream')
;
isStream¶
$this
->resource($variable)
->isStream()
;
- ->is*() va faire correspondre le type du flux au nom d’une méthode :
- ->isFooBar() va essayer de trouver un flux correspondant à foo bar, fooBar, foo_bar…
type¶
$this
->resource($variable)
->type
->isEqualTo('stream')
->matches('/foo.*bar/')
;
->$type est un helper fournissant l’assertion des string sur le type de stream.
sizeOf¶
C’est l’assertion dédiée aux tests sur la taille des tableaux et des objets implémentant l’interface Countable
.
<?php
$array = array(1, 2, 3);
$countableObject = new GlobIterator('*');
$this
->sizeOf($array)
->isEqualTo(3)
->sizeOf($countableObject)
->isGreaterThan(0)
;
isEqualTo¶
Voir aussi
isEqualTo
est une méthode héritée de l’asserter variable
.
Pour plus d’informations, reportez-vous à la documentation de variable::isEqualTo
isGreaterThan¶
Voir aussi
isGreaterThan
est une méthode héritée de l’asserter integer
.
Pour plus d’informations, reportez-vous à la documentation de integer::isGreaterThan
isGreaterThanOrEqualTo¶
Voir aussi
isGreaterThanOrEqualTo
est une méthode héritée de l’asserter integer
.
Pour plus d’informations, reportez-vous à la documentation de integer::isGreaterThanOrEqualTo
isIdenticalTo¶
Voir aussi
isIdenticalTo
est une méthode héritée de l’asserter variable
.
Pour plus d’informations, reportez-vous à la documentation de variable::isIdenticalTo
isLessThan¶
Voir aussi
isLessThan
est une méthode héritée de l’asserter integer
.
Pour plus d’informations, reportez-vous à la documentation de integer::isLessThan
isLessThanOrEqualTo¶
Voir aussi
isLessThanOrEqualTo
est une méthode héritée de l’asserter integer
.
Pour plus d’informations, reportez-vous à la documentation de integer::isLessThanOrEqualTo
isNotEqualTo¶
Voir aussi
isNotEqualTo
est une méthode héritée de l’asserter variable
.
Pour plus d’informations, reportez-vous à la documentation de variable::isNotEqualTo
isNotIdenticalTo¶
Voir aussi
isNotIdenticalTo
est une méthode héritée de l’asserter variable
.
Pour plus d’informations, reportez-vous à la documentation de variable::isNotIdenticalTo
isZero¶
Voir aussi
isZero
est une méthode héritée de l’asserter integer
.
Pour plus d’informations, reportez-vous à la documentation de integer::isZero
stream¶
C’est l’assertion dédié au ´streams <http://php.net/intro.stream>´_.
Elle est basée sur le système de fichier virtuel d’atoum (VFS). Un nouveau stream wrapper sera enregistré (qui commence par atoum://
).
Le bouchon va créer un nouveau fichier dans le VFS et le chemin du flux sera accessible en appellant la méthode getPath
sur le controlleur de flux (par exemple atoum://mockUniqId
).
isRead¶
isRead
vérifie si le flux bouchoné à bien été lu.
<?php
$this
->given(
$streamController = \atoum\mock\stream::get(),
$streamController->file_get_contents = 'myFakeContent'
)
->if(file_get_contents($streamController->getPath()))
->stream($streamController)
->isRead() // passe
;
$this
->given(
$streamController = \atoum\mock\stream::get(),
$streamController->file_get_contents = 'myFakeContent'
)
->if() //we do nothing
->stream($streamController)
->isRead() // échoue
;
isWritten¶
isWritten
vérifie si le flux bouchoné à bien été écrit.
<?php
$this
->given(
$streamController = \atoum\mock\stream::get(),
$streamController->file_put_contents = strlen($content = 'myTestContent')
)
->if(file_put_contents($streamController->getPath(), $content))
->stream($streamController)
->isWritten() // passe
;
$this
->given(
$streamController = \atoum\mock\stream::get(),
$streamController->file_put_contents = strlen($content = 'myTestContent')
)
->if() // we do nothing
->stream($streamController)
->isWritten() // échoue
;
isWrited¶
Indication
isWrited
est un alias de la méthode isWritten
.
Pour plus d’informations, reportez-vous à la documentation de stream::isWritten
string¶
C’est l’assertion dédiée aux chaînes de caractères.
contains¶
contains
vérifie qu’une chaîne de caractère contient une autre chaîne de caractère donnée.
<?php
$string = 'Hello world';
$this
->string($string)
->contains('ll') // passe
->contains(' ') // passe
->contains('php') // échoue
;
endWith¶
endWith
vérifie qu’une chaîne de caractère se termine par une autre chaîne de caractère donnée.
<?php
$string = 'Hello world';
$this
->string($string)
->endWith('world') // passe
->endWith('lo world') // passe
->endWith('Hello') // échoue
->endWith(' ') // échoue
;
hasLength¶
hasLength
vérifie la taille de la chaîne de caractère.
<?php
$string = 'Hello world';
$this
->string($string)
->hasLength(11) // passe
->hasLength(20) // échoue
;
hasLengthGreaterThan¶
hasLengthGreaterThan
vérifie que la taille d’une chaîne de caractères est plus grande qu’une valeur donnée.
<?php
$string = 'Hello world';
$this
->string($string)
->hasLengthGreaterThan(10) // passe
->hasLengthGreaterThan(20) // échoue
;
hasLengthLessThan¶
hasLengthLessThan
vérifie que la taille d’une chaîne de caractères est plus petite qu’une valeur donnée.
<?php
$string = 'Hello world';
$this
->string($string)
->hasLengthLessThan(20) // passe
->hasLengthLessThan(10) // échoue
;
isEmpty¶
isEmpty
vérifie qu’une chaîne de caractères est vide.
<?php
$emptyString = '';
$nonEmptyString = 'atoum';
$this
->string($emptyString)
->isEmpty() // passe
->string($nonEmptyString)
->isEmpty() // échoue
;
isEqualTo¶
Voir aussi
isEqualTo
est une méthode héritée de l’asserter variable
.
Pour plus d’informations, reportez-vous à la documentation de variable::isEqualTo
isEqualToContentsOfFile¶
isEqualToContentsOfFile
vérifie qu’une chaîne de caractère est égale au contenu d’un fichier donné par son chemin.
<?php
$this
->string($string)
->isEqualToContentsOfFile('/path/to/file')
;
Note
si le fichier n’existe pas, le test échoue.
isIdenticalTo¶
Voir aussi
isIdenticalTo
est une méthode héritée de l’asserter variable
.
Pour plus d’informations, reportez-vous à la documentation de variable::isIdenticalTo
isNotEmpty¶
isNotEmpty
vérifie qu’une chaîne de caractères n’est pas vide.
<?php
$emptyString = '';
$nonEmptyString = 'atoum';
$this
->string($emptyString)
->isNotEmpty() // échoue
->string($nonEmptyString)
->isNotEmpty() // passe
;
isNotEqualTo¶
Voir aussi
isNotEqualTo
est une méthode héritée de l’asserter variable
.
Pour plus d’informations, reportez-vous à la documentation de variable::isNotEqualTo
isNotIdenticalTo¶
Voir aussi
isNotIdenticalTo
est une méthode héritée de l’asserter variable
.
Pour plus d’informations, reportez-vous à la documentation de variable::isNotIdenticalTo
length¶
length
vous permet de récupérer un asserter de type integer contenant la taille de la chaîne de caractères testée.
<?php
$string = 'atoum';
$this
->string($string)
->length
->isGreaterThanOrEqualTo(5)
;
match¶
Indication
match
est un alias de la méthode matches
.
Pour plus d’informations, reportez-vous à la documentation de string::matches
matches¶
matches
vérifie qu’une expression régulière correspond à la chaîne de caractères.
<?php
$phone = '0102030405';
$vdm = "Aujourd'hui, à 57 ans, mon père s'est fait tatouer une licorne sur l'épaule. VDM";
$this
->string($phone)
->matches('#^0[1-9]\d{8}$#')
->string($vdm)
->matches("#^Aujourd'hui.*VDM$#")
;
notContains¶
notContains
vérifie qu’une chaîne de caractère ne contient pas une autre chaîne de caractère donnée.
<?php
$string = 'Hello world';
$this
->string($string)
->notContains('php') // passe
->notContains(';') // passe
->notContains('ll') // échoue
->notContains(' ') // échoue
;
notEndWith¶
notEndWith
vérifie qu’une chaîne de caractère ne se termine pas par une autre chaîne de caractère donnée.
<?php
$string = 'Hello world';
$this
->string($string)
->notEndWith('Hello') // passe
->notEndWith(' ') // passe
->notEndWith('world') // échoue
->notEndWith('lo world') // échoue
;
notMatches¶
notMatches
vérifie qu’une expression régulière ne correspond pas à la chaîne de caractères.
<?php
$phone = '0102030405';
$vdm = "Aujourd'hui, à 57 ans, mon père s'est fait tatouer une licorne sur l'épaule. VDM";
$this
->string($phone)
->notMatches('#azerty#') // passe
->notMatches('#^0[1-9]\d{8}$#') // échoue
->string($vdm)
->notMatches("#^Hier.*VDM$#") // passe
->notMatches("#^Aujourd'hui.*VDM$#") // échoue
;
notStartWith¶
notStartWith
vérifie qu’une chaîne de caractère ne commence pas par une autre chaîne de caractère donnée.
<?php
$string = 'Hello world';
$this
->string($string)
->notStartWith('world') // passe
->notStartWith(' ') // passe
->notStartWith('Hello wo') // échoue
->notStartWith('He') // échoue
;
startWith¶
startWith
vérifie qu’une chaîne de caractère commence par une autre chaîne de caractère donnée.
<?php
$string = 'Hello world';
$this
->string($string)
->startWith('Hello wo') // passe
->startWith('He') // passe
->startWith('world') // échoue
->startWith(' ') // échoue
;
Nouveau dans la version 3.3.0: Ajout de l’assertion notMatches
utf8String¶
C’est l’assertion dédiée aux chaînes de caractères UTF-8.
Note
utf8Strings
utilise les fonctions mb_*
pour gérer les chaînes multioctets. Reportez-vous au manuel de PHP pour avoir plus d’information sur l’extension mbstring.
contains¶
Voir aussi
contains
est une méthode héritée de l’asserter string
.
Pour plus d’informations, reportez-vous à la documentation de string::contains
hasLength¶
Voir aussi
hasLength
est une méthode héritée de l’asserter string
.
Pour plus d’informations, reportez-vous à la documentation de string::hasLength
hasLengthGreaterThan¶
Voir aussi
hasLengthGreaterThan
est une méthode héritée de l’asserter string
.
Pour plus d’informations, reportez-vous à la documentation de string::hasLengthGreaterThan
hasLengthLessThan¶
Voir aussi
hasLengthLessThan
est une méthode héritée de l’asserter string
.
Pour plus d’informations, reportez-vous à la documentation de string::hasLengthLessThan
isEmpty¶
Voir aussi
isEmpty
est une méthode héritée de l’asserter string
.
Pour plus d’informations, reportez-vous à la documentation de string::isEmpty
isEqualTo¶
Voir aussi
isEqualTo
est une méthode héritée de l’asserter variable
.
Pour plus d’informations, reportez-vous à la documentation de variable::isEqualTo
isEqualToContentsOfFile¶
Voir aussi
isEqualToContentsOfFile
est une méthode héritée de l’asserter string
.
Pour plus d’informations, reportez-vous à la documentation de string::isEqualToContentsOfFile
isIdenticalTo¶
Voir aussi
isIdenticalTo
est une méthode héritée de l’asserter variable
.
Pour plus d’informations, reportez-vous à la documentation de variable::isIdenticalTo
isNotEmpty¶
Voir aussi
isNotEmpty
est une méthode héritée de l’asserter string
.
Pour plus d’informations, reportez-vous à la documentation de string::isNotEmpty
isNotEqualTo¶
Voir aussi
isNotEqualTo
est une méthode héritée de l’asserter variable
.
Pour plus d’informations, reportez-vous à la documentation de variable::isNotEqualTo
isNotIdenticalTo¶
Voir aussi
isNotIdenticalTo
est une méthode héritée de l’asserter variable
.
Pour plus d’informations, reportez-vous à la documentation de variable::isNotIdenticalTo
matches¶
Indication
matches
est une méthode héritée de l’asserter string
.
Pour plus d’informations, reportez-vous à la documentation de string::matches
Note
Pensez à bien ajouter u
comme option de recherche dans votre expression régulière.
Pour plus de précision, lisez la documentation PHP sur les options de recherche des expressions régulières.
<?php
$vdm = "Aujourd'hui, à 57 ans, mon père s'est fait tatouer une licorne sur l'épaule. FML";
$this
->utf8String($vdm)
->matches("#^Aujourd'hui.*VDM$#u")
;
notContains¶
Voir aussi
notContains
est une méthode héritée de l’asserter string
.
Pour plus d’informations, reportez-vous à la documentation de string::notContains
variable¶
C’est l’assertion de base de toutes les variables. Elle contient les tests nécessaires à n’importe quel type de variable.
isCallable¶
isCallable
vérifie que la variable peut être appelée comme fonction.
<?php
$f = function() {
// code
};
$this
->variable($f)
->isCallable() // passe
->variable('\Vendor\Project\foobar')
->isCallable()
->variable(array('\Vendor\Project\Foo', 'bar'))
->isCallable()
->variable('\Vendor\Project\Foo::bar')
->isCallable()
;
isEqualTo¶
isEqualTo
vérifie que la variable est égale à une certaine donnée.
<?php
$a = 'a';
$this
->variable($a)
->isEqualTo('a') // passe
;
Avertissement
isEqualTo
ne teste pas le type de la variable.isIdenticalTo¶
isIdenticalTo
vérifie que la variable a la même valeur et le même type qu’une certaine donnée. Dans le cas d’objets, isIdenticalTo
vérifie que les données pointent sur la même instance.
<?php
$a = '1';
$this
->variable($a)
->isIdenticalTo(1) // échoue
;
$stdClass1 = new \StdClass();
$stdClass2 = new \StdClass();
$stdClass3 = $stdClass1;
$this
->variable($stdClass1)
->isIdenticalTo(stdClass3) // passe
->isIdenticalTo(stdClass2) // échoue
;
Avertissement
isIdenticalTo
teste le type de la variable.isNotCallable¶
isNotCallable
vérifie que la variable ne peut pas être appelée comme fonction.
<?php
$f = function() {
// code
};
$int = 1;
$string = 'nonExistingMethod';
$this
->variable($f)
->isNotCallable() // échoue
->variable($int)
->isNotCallable() // passe
->variable($string)
->isNotCallable() // passe
->variable(new StdClass)
->isNotCallable() // passe
;
isNotEqualTo¶
isNotEqualTo
vérifie que la variable n’a pas la même valeur qu’une certaine donnée.
<?php
$a = 'a';
$aString = '1';
$this
->variable($a)
->isNotEqualTo('b') // passe
->isNotEqualTo('a') // échoue
->variable($aString)
->isNotEqualTo($a) // échoue
;
Avertissement
isNotEqualTo
ne teste pas le type de la variable.isNotIdenticalTo¶
isNotIdenticalTo
vérifie que la variable n’a ni le même type ni la même valeur qu’une certaine donnée.
Dans le cas d’objets, isNotIdenticalTo
vérifie que les données ne pointent pas sur la même instance.
<?php
$a = '1';
$this
->variable($a)
->isNotIdenticalTo(1) // passe
;
$stdClass1 = new \StdClass();
$stdClass2 = new \StdClass();
$stdClass3 = $stdClass1;
$this
->variable($stdClass1)
->isNotIdenticalTo(stdClass2) // passe
->isNotIdenticalTo(stdClass3) // échoue
;
Avertissement
isNotIdenticalTo
teste le type de la variable.isNull¶
isNull
vérifie que la variable est nulle.
<?php
$emptyString = '';
$null = null;
$this
->variable($emptyString)
->isNull() // échoue
// (c'est vide, mais pas null)
->variable($null)
->isNull() // passe
;
isNotNull¶
isNotNull
vérifie que la variable n’est pas nulle.
<?php
$emptyString = '';
$null = null;
$this
->variable($emptyString)
->isNotNull() // passe (c'est vide, mais pas null)
->variable($null)
->isNotNull() // échoue
;
isNotTrue¶
isNotTrue
vérifie que la variable n’est strictement pas égale à true
.
<?php
$true = true;
$false = false;
$this
->variable($true)
->isNotTrue() // échoue
->variable($false)
->isNotTrue() // passe
;
isNotFalse¶
isNotFalse
vérifie que la variable n’est strictement pas égale à false
.
<?php
$true = true;
$false = false;
$this
->variable($false)
->isNotFalse() // échoue
->variable($true)
->isNotFalse() // passe
;
Asserter & assertion trucs et astuces¶
Plusieurs trucs et astuces sont disponibles pour les assertions. Les connaître peuvent simplifier votre vie ;)
Le premier est que chaque assertion est fluent (chaînable). Donc vous pouvez les enchaîner, il suffit de regarder les exemples précédents.
Vous devez également savoir que toutes les assertions sans paramètres peuvent être écrites avec ou sans parenthèses.
Donc $this->integer(0)->isZero()
est la même chose que $this->integer(0)->isZero
.
Alias¶
Parfois, vous voulez utiliser quelque chose qui reflètent votre vocabulaire ou votre domaine. atoum fournis un mécanisme simple, les alias. En voici un exemple :
<?php
namespace tests\units;
use mageekguy\atoum;
class stdClass extends atoum\test
{
public function __construct(adapter $adapter = null, annotations\extractor $annotationExtractor = null, asserter\generator $asserterGenerator = null, test\assertion\manager $assertionManager = null, \closure $reflectionClassFactory = null)
{
parent::__construct($adapter, $annotationExtractor, $asserterGenerator, $assertionManager, $reflectionClassFactory);
$this
->from('string')->use('isEqualTo')->as('equals')
;
}
public function testFoo()
{
$this
->string($u = uniqid())->equals($u)
;
}
}
Dans cet exemple, nous créons un alias pour faire un nouvel asserter equal```qui agira de la même manière que
``isEqualTo
. Vous pouvez utiliser beforeTestMethod à la place du constructeur. Afin de partager ces alias entre les différents tests, le mieux est de
créer une classe de base pour vos tests à l’intérieur de votre projet que vous pourrez étendre à la place \atoum\test
.
Asserter personnalisé¶
Maintenant que nous avons vu alias, nous pouvons aller plus loin en créant un asserter personnalisé. Voici un exemple d’un asserter pour carte de crédit.
<?php
namespace tests\units;
use mageekguy\atoum;
class creditcard extends atoum\asserters\string
{
public function isValid($failMessage = null)
{
return $this->match('/(?:\d{4}){4}/', $failMessage ?: $this->_('%s is not a valid credit card number', $this));
}
}
class stdClass extends atoum\test
{
public function __construct(adapter $adapter = null, annotations\extractor $annotationExtractor = null, asserter\generator $asserterGenerator = null, test\assertion\manager $assertionManager = null, \closure $reflectionClassFactory = null)
{
parent::__construct($adapter, $annotationExtractor, $asserterGenerator, $assertionManager, $reflectionClassFactory);
$this->getAsserterGenerator()->addNamespace('tests\units');
}
public function testFoo()
{
$this
->creditcard('4444555566660000')->isValid()
;
}
}
Tout comme pour un alias, il est conseillé de créer une classe de base pour vos tests et déclarer l’asserter personnalisé à cet endroit.
Syntaxe courte¶
Avec un alias vous pouvez définir plusieurs choses intéressantes. Afin de vous aider dans la rédaction de vos tests, plusieurs alias sont disponibles nativement.
- == est la même chose que l’asserter isEqualTo
- === est la même chose que l’asserter isIdenticalTo
- != est la même chose que l’asserter isNotEqualTo
- !== est la même chose que l’asserter isNotIdenticalTo
- < est équivalent à isLessThan
- <= est la même chose que l’asserter isLessThanOrEqualTo
- > est la même chose que l’asserter isGreaterThan
- >= est la même chose que l’asserter isGreaterThanOrEqualTo
<?php
namespace tests\units;
use atoum;
class stdClass extends atoum
{
public function testFoo()
{
$this
->variable('foo')->{'=='}('foo')
->variable('foo')->{'foo'} // équivalent à la ligne précédente
->variable('foo')->{'!='}('bar')
->object($this->newInstance)->{'=='}($this->newInstance)
->object($this->newInstance)->{'!='}(new \exception)
->object($this->newTestedInstance)->{'==='}($this->testedInstance)
->object($this->newTestedInstance)->{'!=='}($this->newTestedInstance)
->integer(rand(0, 10))->{'<'}(11)
->integer(rand(0, 10))->{'<='}(10)
->integer(rand(0, 10))->{'>'}(-1)
->integer(rand(0, 10))->{'>='}(0)
;
}
}
Système de mocks¶
Les mocks(bouchons) sont des classes virtuels créer à la volée. Ils sont utilisé pour isolé les tests du comportements des autres classes. atoum a un système de mock simple et puissant, permettant de générer des mocks depuis une classe ou une interface qui existe ou est virtuel, ou encore est abstraite.
Grâce à ces bouchons, vous pourrez simuler des comportements en redéfinissant les méthodes publiques de vos classes. Pour les méthodes private et protected, vous pouvez utiliser l’extension de visibilité.
Avertissement
La plupart de méthode qui configurent le mock, s’appliquent uniquement pour la prochaine génération de ceux-ci!
Générer un bouchon¶
Il y a plusieurs manières de créer un bouchon à partir d’une interface ou d’une classe. Le plus simple est de créer un
objet avec le nom absolu préfixé de mock
:
<?php
// création d'un bouchon de l'interface \Countable
$countableMock = new \mock\Countable;
// création d'un bouchon de la classe abstraite
// \Vendor\Project\AbstractClass
$vendorAppMock = new \mock\Vendor\Project\AbstractClass;
// creation of mock of the \StdClass class
$stdObject = new \mock\StdClass;
// création d'un bouchon à partir d'une classe inexistante
$anonymousMock = new \mock\My\Unknown\Claass;
Générer un mock avec newMockInstance¶
Si vous préférez il existe une méthode newMockInstance()
qui permet la génération d’un mock.
<?php
// création d'un bouchon de l'interface \Countable
$countableMock = new \mock\Countable;
// est équivalent à
$this->newMockInstance('Countable');
Note
Comme le générateur de mock, vous pouvez fournir des paramètres en plus : $this->newMockInstance('class name', 'mock namespace', 'mock class name', ['constructor args']);
Le générateur de bouchon¶
atoum s’appuie sur un composant spécialisé pour générer les bouchons : le mockGenerator
.
Vous avez accès à ce dernier dans vos tests afin de modifier la procédure de génération des mocks.
Par défaut, le mock sera généré dans le namespace « mock » et fonctionnera exactement de la même manière que l’instance de la classe originale (le mock hérite directement de la classe d’origine).
Changer le nom de la classe¶
Si vous désirez changer le nom de la classe ou son espace de nom, vous devez utiliser le mockGenerator
.
La méthode generate
prend trois paramètres :
- le nom de l’interface ou de la classe à bouchonner ;
- le nouvel espace de nom, optionnel ;
- le nouveau nom de la classe, optionnel.
<?php
// création d'un bouchon de l'interface \Countable vers \MyMock\Countable
// on ne change que l'espace de nom
$this->mockGenerator->generate('\Countable', '\MyMock');
// création d'un bouchon de la classe abstraite
// \Vendor\Project\AbstractClass to \MyMock\AClass
// on change l'espace de nom et le nom de la classe
$this->mockGenerator->generate('\Vendor\Project\AbstractClass', '\MyMock', 'AClass');
// création d'un bouchon de la classe \StdClass vers \mock\OneClass
// on ne change que le nom de la classe
$this->mockGenerator->generate('\StdClass', null, 'OneClass');
// on peut maintenant instancier ces mocks
$vendorAppMock = new \myMock\AClass;
$countableMock = new \myMock\Countable;
$stdObject = new \mock\OneClass;
Note
Si vous n’utilisez que le premier argument et ne changez pas le namespace ou le nom de la classe, alors la première solution est équivalente, plus simple à lire et recommandée.
Vous pouvez accéder au code généré pour la classe par le générateur de mock en appelant
$this->mockGenerator->getMockedClassCode()
, pour débuguer par exemple. Cette
méthode prend les mêmes arguments que la méthode generate
.
<?php
$countableMock = new \mock\Countable;
// est équivalent à:
$this->mockGenerator->generate('\Countable'); // inutile
$countableMock = new \mock\Countable;
Note
Tout ce qui est décrit ici avec le générateur de mock peut être utilisé avec newMockInstance
Shunter les appels aux méthodes parentes¶
shuntParentClassCalls & unShuntParentClassCalls¶
Un bouchon hérite directement de la classe à partir de laquelle il a été généré, ses méthodes se comportent donc exactement de la même manière.
Dans certains cas, il peut être utile de shunter les appels aux méthodes parentes afin que leur code ne soit plus exécuté.
Le mockGenerator
met à votre disposition plusieurs méthodes pour y parvenir :
<?php
// le bouchon ne fera pas appel à la classe parente
$this->mockGenerator->shuntParentClassCalls();
$mock = new \mock\OneClass;
// le bouchon fera à nouveau appel à la classe parente
$this->mockGenerator->unshuntParentClassCalls();
Ici, toutes les méthodes du bouchon se comporteront comme si elles n’avaient pas d’implémentation par contre elles conserveront la signature des méthodes originales.
Note
shuntParentClassCalls
va seulement être appliqué à la prochaine génération de mock. Mais si vous créer deux mock de la même classe,
les deux auront leurs méthodes parente shunté.
shunt¶
Vous pouvez également préciser les méthodes que vous souhaitez shunter :
<?php
// le bouchon ne fera pas appel à la classe parente pour la méthode firstMethod…...
$this->mockGenerator->shunt('firstMethod');
// ... ni pour la méthode secondMethod
$this->mockGenerator->shunt('secondMethod');
$countableMock = new \mock\OneClass;
Une méthode shuntée aura un corps de méthode vide mais comme pour shuntParentClassCalls
la signature de la méthode sera la même que celle bouchonée.
Rendre une méthode orpheline¶
Il peut parfois être intéressant de rendre une méthode orpheline, c’est-à-dire, lui donner une signature et une implémentation vide. Cela peut être particulièrement utile pour générer des bouchons sans avoir à instancier toutes leurs dépendances. Tous les paramètres de la méthode seront également définis avec comme valeur par défaut null. C’est donc la même chose que shunter une méthode mais avec tout les paramètres a null.
<?php
class FirstClass {
protected $dep;
public function __construct(SecondClass $dep) {
$this->dep = $dep;
}
}
class SecondClass {
protected $deps;
public function __construct(ThirdClass $a, FourthClass $b) {
$this->deps = array($a, $b);
}
}
$this->mockGenerator->orphanize('__construct');
$this->mockGenerator->shuntParentClassCalls();
// Nous pouvons instancier le bouchon sans injecter ses dépendances
$mock = new \mock\SecondClass();
$object = new FirstClass($mock);
Note
orphanize
va seulement être appliqué à la prochaine génération de mock.
Modifier le comportement d’un bouchon¶
Une fois le bouchon créé et instancié, il est souvent utile de pouvoir modifier le comportement de ses méthodes. Pour cela, il faut passer par son contrôleur en utilisant l’une des méthodes suivantes :
- $yourMock->getMockController()->yourMethod
- $this->calling($yourMock)->yourMethod
<?php
$mockDbClient = new \mock\Database\Client();
$mockDbClient->getMockController()->connect = function() {};
// Equivalent to
$this->calling($mockDbClient)->connect = function() {};
Le mockController
vous permet de redéfinir uniquement les méthodes publiques et abstraites protégées et met à votre disposition plusieurs méthodes :
<?php
$mockDbClient = new \mock\Database\Client();
// redéfinit la méthode connect : elle retournera toujours true
$this->calling($mockDbClient)->connect = true;
// redéfinit la méthode select : elle exécutera la fonction anonyme passée
$this->calling($mockDbClient)->select = function() {
return array();
};
// redéfinit la méthode query avec des arguments
$result = array();
$this->calling($mockDbClient)->query = function(Query $query) use($result) {
switch($query->type) {
case Query::SELECT:
return $result;
default;
return null;
}
};
// la méthode connect lèvera une exception
$this->calling($mockDbClient)->connect->throw = new \Database\Client\Exception();
Note
La syntaxe utilise les fonctions anonymes (aussi appelées fermetures ou closures) introduites en PHP 5.3. Reportez-vous au manuel de PHP pour avoir plus d’informations sur le sujet.
Comme vous pouvez le voir, il est possible d’utiliser plusieurs méthodes afin d’obtenir le comportement souhaité :
- Utiliser une valeur statique qui sera retournée par la méthode
- Utiliser une implémentation courte grâce aux fonctions anonymes de PHP
- Utiliser le mot-clef
throw
pour lever une exception
Changement de comportement du mock sur plusieurs appels¶
Vous pouvez également spécifier plusieurs valeurs en fonction de l’ordre d’appel :
<?php
// default
$this->calling($mockDbClient)->count = rand(0, 10);
// équivalent à
$this->calling($mockDbClient)->count[0] = rand(0, 10);
// 1er appel
$this->calling($mockDbClient)->count[1] = 13;
// 3ème appel
$this->calling($mockDbClient)->count[3] = 42;
- Le premier appel retournera 13.
- Le second aura le comportement par défaut, c’est-à-dire un nombre aléatoire.
- Le troisième appel retournera 42.
- Tous les appels suivants auront le comportement par défaut, c’est à dire des nombres aléatoires.
Si vous souhaitez que plusieurs méthodes du bouchon aient le même comportement, vous pouvez utiliser les méthodes methods ou methodsMatching.
methods¶
methods
vous permet, grâce à la fonction anonyme passée en argument, de définir pour quelles méthodes le comportement doit être modifié :
<?php
// si la méthode a tel ou tel nom,
// on redéfinit son comportement
$this
->calling($mock)
->methods(
function($method) {
return in_array(
$method,
array(
'getOneThing',
'getAnOtherThing'
)
);
}
)
->return = uniqid()
;
// on redéfinit le comportement de toutes les méthodes
$this
->calling($mock)
->methods()
->return = null
;
// si la méthode commence par "get",
// on redéfinit son comportement
$this
->calling($mock)
->methods(
function($method) {
return substr($method, 0, 3) == 'get';
}
)
->return = uniqid()
;
Dans le cas du dernier exemple, vous devriez plutôt utiliser methodsMatching.
Note
La syntaxe utilise les fonctions anonymes (aussi appelées fermetures ou closures) introduites en PHP 5.3. Reportez-vous au manuel de PHP pour avoir plus d’informations sur le sujet.
methodsMatching¶
methodsMatching
vous permet de définir les méthodes où le comportement doit être modifié grâce à l’expression
rationnelle passée en argument :
<?php
// si la méthode commence par "is",
// on redéfinit son comportement
$this
->calling($mock)
->methodsMatching('/^is/')
->return = true
;
// si la méthode commence par "get" (insensible à la casse),
// on redéfinit son comportement
$this
->calling($mock)
->methodsMatching('/^get/i')
->throw = new \exception
;
Note
methodsMatching
utilise preg_match et les expressions rationnelles. Reportez-vous
au manuel de PHP pour avoir plus d’informations sur le sujet.
isFluent && returnThis¶
Défini une méthode fluent (chaînable), ainsi la méthode appelée retourne l’instance de la classe.
<?php
$foo = new \mock\foo();
$this->calling($foo)->bar = $foo;
// est identique à
$this->calling($foo)->bar->isFluent;
// ou a celui-ci
$this->calling($foo)->bar->returnThis;
doesNothing && doesSomething¶
Changer le comportement du mock avec doesNothing
, la méthode retournera simple null.
<?php
class foo {
public function bar() {
return 'baz';
}
}
//
// in your test
$foo = new \mock\foo();
$this->calling($foo)->bar = null;
// est identique à
$this->calling($foo)->bar->doesNothing;
$this->variable($foo->bar())->isNull;
// restaure le comportement
$this->calling($foo)->bar->doesSomething;
$this->string($foo->bar())->isEqualTo('baz');
Comme on le voix dans l’exemple, si pour une raison quelconque, vous souhaitez rétablir le comportement de la méthode, utilisez doesSomething
.
Cas particulier du constructeur¶
Pour mocker le constructeur de la classe, vous avez besoin de :
- créer une instance de la classe atoummockcontroller avant d’appeler le constructeur du bouchon ;
- définir via ce contrôleur le comportement du constructeur du bouchon à l’aide d’une fonction anonyme ;
- injecter le contrôleur lors de l’instanciation du bouchon en dernier argument.
<?php
$controller = new \atoum\mock\controller();
$controller->__construct = function($args)
{
// faire quelque chose avec les arguments
};
$mockDbClient = new \mock\Database\Client(DB_HOST, DB_USER, DB_PASS, $controller);
Pour les cas simple, vous pouvez utiliser orphanize(“__constructor”) ou shunt(“__constructor”).
Tester un bouchon¶
atoum vous permet de vérifier qu’un bouchon a été utilisé correctement.
<?php
$mockDbClient = new \mock\Database\Client();
$mockDbClient->getMockController()->connect = function() {};
$mockDbClient->getMockController()->query = array();
$bankAccount = new \Vendor\Project\Bank\Account();
$this
// utilisation du bouchon via un autre objet
->array($bankAccount->getOperations($mockDbClient))
->isEmpty()
// test du bouchon
->mock($mockDbClient)
->call('query')
->once() // vérifie que la méthode query
// n'a été appelé qu'une seule fois
;
Note
Reportez-vous à la documentation sur l’assertion mock pour obtenir plus d’informations sur les tests des bouchons.
Le bouchonnage (mock) des fonctions natives de PHP¶
atoum permet de très facilement simuler le comportement des fonctions natives de PHP.
<?php
$this
->assert('the file exist')
->given($this->newTestedInstance())
->if($this->function->file_exists = true)
->then
->object($this->testedInstance->loadConfigFile())
->isTestedInstance()
->function('file_exists')->wasCalled()->once()
->assert('le fichier does not exist')
->given($this->newTestedInstance())
->if($this->function->file_exists = false )
->then
->exception(function() { $this->testedInstance->loadConfigFile(); })
;
Important
On ne peut pas mettre de \ devant les fonctions à simuler, car atoum s’appuie sur le mécanisme de résolution des espaces de nom de PHP.
Important
Pour la même raison, si une fonction native a déjà été appelée, son bouchonnage sera sans effet.
<?php
$this
->given($this->newTestedInstance())
->exception(function() { $this->testedInstance->loadConfigFile(); }) //la fonction file_exists est appelée avant son bouchonnage
->if($this->function->file_exists = true ) // le bouchonnage ne pourra pas prendre la place de la fonction native file_exists
->object($this->testedInstance->loadConfigFile())
->isTestedInstance()
;
Note
Plus d’information via isTestedInstance().
Les bouchons de constantes¶
Les constantes PHP peuvent être déclarées avec defined
, cependant avec atoum vous pouvez les bouchonner de cette manière :
<?php
$this->constant->PHP_VERSION_ID = '606060'; // troll \o/
$this
->given($this->newTestedInstance())
->then
->variable($this->testedInstance->hello())->isEqualTo(PHP_VERSION_ID)
->if($this->constant->PHP_VERSION_ID = uniqid())
->then
->variable($this->testedInstance->hello())->isEqualTo(PHP_VERSION_ID)
;
Attention, due à la nature des constantes en PHP, suivant l’engine utilisé vous pouvez rencontrer différents problèmes. En voici un exemple :
<?php
namespace foo {
class foo {
public function hello()
{
return PHP_VERSION_ID;
}
}
}
namespace tests\units\foo {
use atoum;
/**
* @engine inline
*/
class foo extends atoum
{
public function testFoo()
{
$this
->given($this->newTestedInstance())
->then
->variable($this->testedInstance->hello())->isEqualTo(PHP_VERSION_ID)
->if($this->constant->PHP_VERSION_ID = uniqid())
->then
->variable($this->testedInstance->hello())->isEqualTo(PHP_VERSION_ID)
;
}
public function testBar()
{
$this
->given($this->newTestedInstance())
->if($this->constant->PHP_VERSION_ID = $mockVersionId = uniqid()) // inline engine will fail here
->then
->variable($this->testedInstance->hello())->isEqualTo($mockVersionId)
->if($this->constant->PHP_VERSION_ID = $mockVersionId = uniqid()) // isolate/concurrent engines will fail here
->then
->variable($this->testedInstance->hello())->isEqualTo($mockVersionId)
;
}
}
}
Les moteurs d’exécution¶
Plusieurs moteurs d’exécution des tests (au niveau de la classe ou des méthodes) existent. Ceci est configuré via l’annotation @engine
. Par défaut, les différents tests s’exécutent en parallèle, dans des sous-processus PHP, c’est le mode concurrent
.
Il existe actuellement trois moteurs d’exécution :
- inline : les tests s’exécutent dans le même processus, cela revient au même comportement que PHPUnit. Même si ce mode est très rapide, il n’y a pas d’isolation des tests.
- isolate : les tests s’exécutent de manière séquentielle dans un sous-processus PHP. Ce mode d’exécution est assez lent.
- concurrent : le mode par défaut, les tests s’exécutent en parallèle, dans des sous-processus PHP.
Important
Si vous utilisez xdebug pour déboguer vos tests (et pas seulement pour la couverture de code), le seul moteur d’exécution disponible est concurrent.
Voici un exemple :
<?php
/**
* @engine concurrent
*/
class Foo extends \atoum
{
public function testBarWithBaz()
{
sleep(1);
$this->newTestedInstance;
$baz = new \Baz();
$this->object($this->testedInstance->setBaz($baz))
->isIdenticalTo($this->testedInstance);
$this->string($this->testedInstance->bar())
->isIdenticalTo('baz');
}
public function testBarWithoutBaz()
{
sleep(1);
$this->newTestedInstance;
$this->string($this->testedInstance->bar())
->isIdenticalTo('foo');
}
}
En mode concurent
:
=> Test duration: 2.01 seconds.
=> Memory usage: 0.50 Mb.
> Total test duration: 2.01 seconds.
> Total test memory usage: 0.50 Mb.
> Running duration: 1.08 seconds.
En mode inline
:
=> Test duration: 2.01 seconds.
=> Memory usage: 0.25 Mb.
> Total test duration: 2.01 seconds.
> Total test memory usage: 0.25 Mb.
> Running duration: 2.01 seconds.
En mode isolate
:
=> Test duration: 2.00 seconds.
=> Memory usage: 0.50 Mb.
> Total test duration: 2.00 seconds.
> Total test memory usage: 0.50 Mb.
> Running duration: 2.10 seconds.
Mode répétition¶
Lorsqu’un développeur fait du développement piloté par les tests, il travaille généralement de la manière suivante :
- il commence par créer le test correspondant à ce qu’il veut développer ;
- il exécute ensuite le test qu’il vient de créer ;
- il écrit le code permettant au test de passer avec succès ;
- il modifie ou complète son test et repars à l’étape 2.
Concrètement, cela signifie qu’il doit :
- créer son code dans son éditeur favori ;
- quitter son éditeur puis exécuter son test dans une console ;
- revenir à son éditeur pour écrire le code permettant au test de passer avec succès ;
- revenir à la console afin de relancer l’exécution de son test ;
- revenir à son éditeur afin de modifier ou compléter son test ;
Il y a donc un cycle qui se répète jusqu’à ce que la fonctionnalité soit terminée.
Au cours de ce cycle, le développeur doit à plusieurs reprises exécuter la même commande pour exécuter les tests unitaires.
atoum propose le mode loop
disponible via les arguments -l
ou --loop
, qui permet au développeur de ne pas avoir à relancer manuellement les tests et permet donc de fluidifier le processus de développement.
Dans ce mode, atoum exécute les tests demandés.
Une fois les tests terminés, si les tests ont été passés avec succès, atoum se met simplement en attente :
$ php tests/units/classes/adapter.php -l
> PHP path: /usr/bin/php
> PHP version:
=> PHP 5.6.3 (cli) (built: Nov 13 2014 18:31:57)
=> Copyright (c) 1997-2014 The PHP Group
=> Zend Engine v2.6.0, Copyright (c) 1998-2014 Zend Technologies
> mageekguy\atoum\tests\units\adapter...
[SS__________________________________________________________][2/2]
=> Test duration: 0.00 second.
=> Memory usage: 0.50 Mb.
> Total test duration: 0.00 second.
> Total test memory usage: 0.50 Mb.
> Running duration: 0.05 second.
Success (1 test, 2/2 methods, 0 void method, 0 skipped method, 4 assertions)!
Press <Enter> to reexecute, press any other key and <Enter> to stop...
Si le développeur presse la touche Enter
, atoum réexécutera à nouveau les mêmes tests, sans aucune autre action de la part du développeur.
Dans le cas où le code ne passe pas les tests avec succès, c’est-à-dire si les assertions échouent ou s’il y a des erreurs ou des exceptions, atoum se remet en mode d’attente :
$ php tests/units/classes/adapter.php -l> PHP path: /usr/bin/php
> PHP version:
=> PHP 5.6.3 (cli) (built: Nov 13 2014 18:31:57)
=> Copyright (c) 1997-2014 The PHP Group
=> Zend Engine v2.6.0, Copyright (c) 1998-2014 Zend Technologies
> mageekguy\atoum\tests\units\adapter...
[FS__________________________________________________________][2/2]
=> Test duration: 0.00 second.
=> Memory usage: 0.25 Mb.
> Total test duration: 0.00 second.
> Total test memory usage: 0.25 Mb.
> Running duration: 0.05 second.
Failure (1 test, 2/2 methods, 0 void method, 0 skipped method, 0 uncompleted method, 1 failure, 0 error, 0 exception)!
> There is 1 failure:
=> mageekguy\atoum\tests\units\adapter::test__call():
In file /media/data/dev/atoum-documentation/tests/vendor/atoum/atoum/tests/units/classes/adapter.php on line 16, mageekguy\atoum\asserters\string() failed: strings are not equal
-Expected
+Actual
@@ -1 +1 @@
-string(32) "1305beaa8f3f2f932f508d4af7f89094"
+string(32) "d905c0b86bf89f9a57d4da6101f93648"
Press <Enter> to reexecute, press any other key and <Enter> to stop...
Si le développeur presse la touche Enter
, au lieu de rejouer les mêmes tests, atoum n’exécutera que les tests en échec, au lieu de rejouer l’ensemble.
Le développeur pourra alors dépiler les problèmes et rejouer les tests en erreur autant de fois que nécessaire simplement en appuyant sur Enter
.
De plus, une fois que tous les tests en échec passeront à nouveau avec succès, atoum exécutera automatiquement la totalité de la suite de tests afin de détecter les éventuelles régressions introduites par la ou les corrections effectuées par le développeur.
Press <Enter> to reexecute, press any other key and <Enter> to stop...
> PHP path: /usr/bin/php
> PHP version:
=> PHP 5.6.3 (cli) (built: Nov 13 2014 18:31:57)
=> Copyright (c) 1997-2014 The PHP Group
=> Zend Engine v2.6.0, Copyright (c) 1998-2014 Zend Technologies
> mageekguy\atoum\tests\units\adapter...
[S___________________________________________________________][1/1]
=> Test duration: 0.00 second.
=> Memory usage: 0.25 Mb.
> Total test duration: 0.00 second.
> Total test memory usage: 0.25 Mb.
> Running duration: 0.05 second.
Success (1 test, 1/1 method, 0 void method, 0 skipped method, 2 assertions)!
> PHP path: /usr/bin/php
> PHP version:
=> PHP 5.6.3 (cli) (built: Nov 13 2014 18:31:57)
=> Copyright (c) 1997-2014 The PHP Group
=> Zend Engine v2.6.0, Copyright (c) 1998-2014 Zend Technologies
> mageekguy\atoum\tests\units\adapter...
[SS__________________________________________________________][2/2]
=> Test duration: 0.00 second.
=> Memory usage: 0.50 Mb.
> Total test duration: 0.00 second.
> Total test memory usage: 0.50 Mb.
> Running duration: 0.05 second.
Success (1 test, 2/2 methods, 0 void method, 0 skipped method, 4 assertions)!
Press <Enter> to reexecute, press any other key and <Enter> to stop...
Bien évidemment, le mode loop
ne prend en compte que le ou les fichiers de tests unitaires lancés par atoum.
Débogage des scénarios de test¶
Parfois, un test ne passe pas et il est difficile d’en découvrir la raison.
Dans ce cas, l’une des techniques possibles pour remédier au problème est de tracer le comportement du code concerné, soit directement au cœur de la classe testée à l’aide d’un débogueur ou de fonctions du type de var_dump()
ou print_r()
, soit au niveau du test unitaire.
atoum fourni un certain nombre d’outils pour faciliter la tâche de débogage directement dans les tests unitaires.
Ces outils ne sont cependant actifs que lorsqu’atoum est exécuté à l’aide de l’argument --debug
, afin que l’exécution des tests unitaires ne soit pas perturbée par les instructions relatives au débogage hors de ce contexte.
Lorsque l’argument --debug
est utilisé, trois méthodes peuvent être activée :
dump()
qui permet de connaître le contenu d’une variable ;stop()
qui permet d’arrêter l’exécution d’un test ;executeOnFailure()
qui permet de définir une fonction anonyme qui ne sera exécutée qu’en cas d’échec d’une assertion.
Ces trois méthodes s’intègrent parfaitement dans l’interface fluide qui caractérise atoum.
dump¶
La méthode dump()
peut s’utiliser de la manière suivante :
<?php
$this
->if($foo = new foo())
->then
->object($foo->setBar($bar = new bar()))
->isIdenticalTo($foo)
->dump($foo->getBar())
;
Lors de l’exécution du test, le retour de la méthode foo::getBar()
sera affiché sur la sortie standard.
Il est également possible de passer plusieurs arguments à dump()
, de la manière suivante :
<?php
$this
->if($foo = new foo())
->then
->object($foo->setBar($bar = new bar()))
->isIdenticalTo($foo)
->dump($foo->getBar(), $bar)
;
Important
La méthode dump
n’est activée que si vous lancez les tests avec l’argument --debug
. Dans le cas contraire, cette méthode sera totalement ignorée.
stop¶
L’utilisation de la méthode stop()
est également très simple :
<?php
$this
->if($foo = new foo())
->then
->object($foo->setBar($bar = new bar()))
->isIdenticalTo($foo)
->stop() // le test s'arrêtera ici si --debug est utilisé
->object($foo->getBar())
->isIdenticalTo($bar)
;
Si --debug
est utilisé, les 2 dernières lignes ne seront pas exécutées.
Important
La méthode stop
n’est activée que si vous lancez les tests avec l’argument --debug
. Dans le cas contraire, cette méthode sera totalement ignorée.
executeOnFailure¶
La méthode executeOnFailure()
est très puissante et tout aussi simple à utiliser.
Elle prend en effet en argument une fonction anonyme qui sera exécutée si et seulement si l’une des assertions composant le test n’est pas vérifiée. Elle s’utilise de la manière suivante :
<?php
$this
->if($foo = new foo())
->executeOnFailure(
function() use ($foo) {
var_dump($foo);
}
)
->then
->object($foo->setBar($bar = new bar()))
->isIdenticalTo($foo)
->object($foo->getBar())
->isIdenticalTo($bar)
;
Dans l’exemple précédent, contrairement à dump()
qui provoque systématiquement l’affichage sur la sortie standard le contenu des variables qui lui sont passées en argument, la fonction anonyme passée en argument ne provoquera l’affichage du contenu de la variable foo
que si l’une des assertions suivantes est en échec.
Bien évidemment, il est possible de faire appel plusieurs fois à executeOnFailure()
dans une même méthode de test pour définir plusieurs fonctions anonymes différentes devant être exécutées en cas d’échec du test.
Important
La méthode executeOnFailure
n’est activée que si vous lancez les tests avec l’argument --debug
. Dans le cas contraire, cette méthode sera totalement ignorée.
Ajustement du comportement d’atoum¶
Les méthodes d’initialisation¶
Voici le processus, lorsque atoum exécute les méthodes de test d’une classe avec le moteur par défaut (concurrent
) :
- appel de la méthode
setUp()
de la classe de test ; - lancement d’un sous-processus PHP pour exécuter chaque méthode de test ;
- dans le sous-processus PHP, appel de la méthode
beforeTestMethod()
de la classe de test ; - dans le sous-processus PHP, appel de la méthode de test ;
- dans le sous-processus PHP, appel de la méthode
afterTestMethod()
de la classe de test ; - une fois le sous-processus PHP terminé, appel de la méthode
tearDown()
de la classe de test.
Note
Pour plus d’informations sur les moteurs d’exécution des tests d’atoum, vous pouvez lire le paragraphe sur l’annotation @engine.
Les méthodes setUp()
et tearDown()
permettent donc respectivement d’initialiser et de nettoyer l’environnement de test pour l’ensemble des méthodes de test de la classe exécutée.
Les méthodes beforeTestMethod()
et afterTestMethod()
permet respectivement d’initialiser et de nettoyer l’environnement d’exécution des tests individuels pour toutes les méthodes de test de la classe. À l’opposé setUp()
et tearDown()
, sont exécutées dans le sous-processus lui-même.
C’est d’ailleurs la raison pour laquelle les méthodes beforeTestMethod()
et afterTestMethod()
acceptent comme argument le nom de la méthode de test exécutée, afin de pouvoir ajuster les traitements en conséquence.
<?php
namespace vendor\project\tests\units;
use
mageekguy\atoum,
vendor\project
;
require __DIR__ . '/atoum.phar';
class bankAccount extends atoum
{
public function setUp()
{
// Exécutée *avant l'ensemble* des méthodes de test.
// Initialisation globale.
}
public function beforeTestMethod($method)
{
// Exécutée *avant chaque* méthode de test.
switch ($method)
{
case 'testGetOwner':
// Initialisation pour testGetOwner().
break;
case 'testGetOperations':
// Initialisation pour testGetOperations().
break;
}
}
public function testGetOwner()
{
// ...
}
public function testGetOperations()
{
// ...
}
public function afterTestMethod($method)
{
// Exécutée *après chaque* méthode de test.
switch ($method)
{
case 'testGetOwner':
// Nettoyage pour testGetOwner().
break;
case 'testGetOperations':
// Nettoyage pour testGetOperations().
break;
}
}
public function tearDown()
{
// Exécutée après l'ensemble des méthodes de test.
// Nettoyage global.
}
}
Par défaut, les méthodes setUp()
, beforeTestMethod()
, afterTestMethod()
et tearDown()
ne font absolument rien.
Il est donc de la responsabilité du programmeur de les surcharger lorsque c’est nécessaire dans les classes de test concerné.
Configuration & bootstraping¶
Plusieurs étapes vont se succéder au lancement d’atoum, certaines d’entre elles peuvent être influencées par des fichiers spéciaux.
On peut avoir une vue simplifiée de ces fichiers spéciaux et optionnelle en :
- Chargement de l”autoloader
- Chargement du fichier de configuration
- Chargement du fichier de bootstrap
Note
Vous pouvez utiliser atoum –init pour générer ces fichiers.
L’autoloader¶
Le fichier d’autoload (autoloader) est ce que vous allez utiliser pour définir comment atoum va trouver la classe à tester.
Le nom du fichier par défaut est .autoloader.atoum.php
. atoum le chargera automatiquement s’il se trouve dans le dossier courant. Vous pouvez le définir dans la ligne de commande avec --autoloader-file
ou -af
(voir les options de la ligne de commande). L’objectif du fichier d’autoloader est de permettre de charger les classes nécessaire pour exécuter les tests. Vous pouvez trouver plus d’informations sur
l’auto-chargement des classes dans le manuel php.
Si l’autoloader n’existe pas, atoum essayera de charger le fichier vendor/autoload.php
de composer. Vous n’aurez donc rien à faire dans la majorité des cas. ;).
Fichier de configuration¶
Le fichier de configuration vous permet de configurer comment atoum fonctionne.
Si vous nommez votre fichier de configuration .atoum.php
, atoum le chargera automatiquement si ce fichier se trouve dans le répertoire courant. Le paramètre -c
est donc optionnel dans ce cas.
Note
La configuration de atoum supporte l’héritage de fichier. Si vous avez un fichier .atoum.php
dans le répertoire parent, il sera également chargé.
Vous pouvez ainsi avoir un fichier de configuration par défaut afin d’avoir le mode loop ou debug activé par défaut.
Exemple existant¶
atoum fourni un fichier d’exemple basique. Suivant le type d’installation de atoum, il y a plusieurs façons de les voir :
Depuis une installation PHAR¶
Si vous utlisez l’archive PHAR, il faut les extraire en utilisant la commande suivante :
php atoum.phar -er /path/to/destination/directory
Une fois l’extraction effectuée, vous devriez avoir dans le répertoire /path/to/destination/directory un répertoire nommé resources/configurations/runner.
Couverture du code¶
Par défaut, si PHP dispose de l’extension Xdebug, atoum indique en ligne de commande le taux de couverture du code par les tests venant d’être exécutés. Certains comportements de la couverture de code peuvent être adaptés via les options de l’interface en ligne de commande.
Si le taux de couverture est de 100%, atoum se contente de l’indiquer. Mais dans le cas contraire, il affiche le taux de couverture globale ainsi que celui de chaque méthode de la classe testée sous la forme d’un pourcentage.
$ php tests/units/classes/template.php
> atoum version DEVELOPMENT by Frederic Hardy (/Users/fch/Atoum)
> PHP path: /usr/local/bin/php
> PHP version:
=> PHP 5.3.8 (cli) (built: Sep 21 2011 23:14:37)
=> Copyright (c) 1997-2011 The PHP Group
=> Zend Engine v2.3.0, Copyright (c) 1998-2011 Zend Technologies
=> with Xdebug v2.1.1, Copyright (c) 2002-2011, by Derick Rethans
> mageekguy\atoum\tests\units\template...
[SSSSSSSSSSSSSSSSSSSSSSSSSSS_________________________________][27/27]
=> Test duration: 15.63 seconds.
=> Memory usage: 8.25 Mb.
> Total test duration: 15.63 seconds.
> Total test memory usage: 8.25 Mb.
> Code coverage value: 92.52%
=> Class mageekguy\atoum\template: 91.14%
==> mageekguy\atoum\template::setWith(): 80.00%
==> mageekguy\atoum\template::resetChildrenData(): 25.00%
==> mageekguy\atoum\template::addToParent(): 0.00%
==> mageekguy\atoum\template::unsetAttribute(): 0.00%
=> Class mageekguy\atoum\template\data: 96.43%
==> mageekguy\atoum\template\data::__toString(): 0.00%
> Running duration: 2.36 seconds.
Success (1 test, 27 methods, 485 assertions, 0 error, 0 exception) !
Il est cependant possible d’obtenir une représentation plus précise du taux de couverture du code par les tests, sous la forme d’un rapport au format HTML. Cela peut être trouver dans l’extension report.
Rapport de couverture personnalisée¶
Dans ce répertoire, il y a, entre autre chose intéressante, un modèle de fichier de configuration pour atoum nommé coverage.php.dist
qu’il vous faudra copier à l’emplacement de votre choix. Renommez le coverage.php
.
Une fois le fichier copié, il n’y a plus qu’à le modifier à l’aide de l’éditeur de votre choix afin de définir le répertoire dans lequel les fichiers HTML devront être générés ainsi que l’URL à partir de laquelle le rapport devra être accessible.
Par exemple :
$coverageField = new atoum\report\fields\runner\coverage\html(
'Code coverage de mon projet',
'/path/to/destination/directory'
);
$coverageField->setRootUrl('http://url/of/web/site');
Note
Il est également possible de modifier le titre du rapport à l’aide du premier argument du constructeur de la classe mageekguy\atoum\report\fields\runner\coverage\html
.
Une fois ceci en place, vous avez simplement a utiliser le fichier de configuration (ou l’inclure dans le fichier de configuration) lorsque vous lancer les tests, comme ceci :
$ ./bin/atoum -c path/to/coverage.php -d tests/units
Une fois les tests exécutés, atoum génèrera alors le rapport de couverture du code au format HTML dans le répertoire que vous aurez défini précédemment, et il sera lisible à l’aide du navigateur de votre choix.
Note
Le calcul du taux de couverture du code par les tests ainsi que la génération du rapport correspondant peuvent ralentir de manière notable l’exécution des tests. Il peut être alors intéressant de ne pas utiliser systématiquement le fichier de configuration correspondant, ou bien de les désactiver temporairement à l’aide de l’argument -ncc.
Utilisation de rapports standards¶
atoum est fourni avec de nombreux rapports standards : tap, xunit, html, cli, phing, vim, … Il y a aussi quelques rapports funs. Vous trouverez les plus importants ici.
Note
Si vous souhaitez aller plus loin, il y a une extension dédiée aux rapports appelée reports-extension
.
Configuration de rapports¶
Couverture des branches et chemins¶
Dans le fichier de configuration, vous pouvez activer la couverture des branches et chemins à l’aide de l’option enableBranchAndPathCoverage
. Cette action améliorera la qualité de la couverture du code car elle ne se limitera pas à vérifier qu’une fonction est appelée, mais également
que chaque branche l’est également.
Pour faire simple, si vous avez un if
, le rapport changera si vous cherchez le else
. Vous pouvez aussi l’activer via la ligne commande avec l’option –epbc.
$script->enableBranchAndPathCoverage();
=> Class Foo\Bar: Line: 31.46%
# avec la couverture des branches et chemins
=> Class Foo\Bar: Line: 31.46% Path: 1.50% Branch: 26.06%
Désactiver la couverture pour une classe¶
Si vous souhaitez exclure certaines classes de la couverture de code, vous pouvez utiliser $script->noCodeCoverageForClasses(\myClass::class)
.
Rapport HTML¶
Par défaut, atoum fournit un rapport HTML basique. Pour un rapport plus avancé, vous pouvez utiliser reports-extension.
<?php
$report = $script->addDefaultReport();
$coverageField = new atoum\report\fields\runner\coverage\html('Your Project Name', __DIR__ . '/reports');
// Remplacez cette url par l'url racine de votre site de couverture de code.
$coverageField->setRootUrl('http://url/of/web/site');
$report->addField($coverageField);
Rapport CLI¶
Le rapport CLI est celui qui s’affiche quand vous lancez le test. Ce rapport a quelques options de configuration disponibles
- hideClassesCoverageDetails: Désactive la couverture d’une classe.
- hideMethodsCoverageDetails: Désactive la couverture d’une méthode.
<?php
$script->addDefaultReport() // les rapports par défaut incluent celui-ci
->hideClassesCoverageDetails()
->hideMethodsCoverageDetails();
Afficher le logo d’atoum¶
<?php
$report = $script->addDefaultReport();
// Cette ligne ajoute le logo d'atoum à chaque exécution
$report->addField(new atoum\report\fields\runner\atoum\logo());
// Celle-ci va ajouter un logo vert ou rouge après chaque exécution en fonction du status de cette dernière
$report->addField(new atoum\report\fields\runner\result\logo());
Rapport Treemap¶
<?php
$report = $script->addDefaultReport();
$coverageHtmlField = new atoum\report\fields\runner\coverage\html('Your Project Name', __DIR__ . '/reports');
// Remplacez cette url par l'url racine de votre site de couverture de code.
$coverageHtmlField->setRootUrl('http://url/of/web/site');
$report->addField($coverageField);
$coverageTreemapField = new atoum\report\fields\runner\coverage\treemap('Your project name', __DIR__ . '/reports');
$coverageTreemapField
->setTreemapUrl('http://url/of/treemap')
->setHtmlReportBaseUrl($coverageHtmlField->getRootUrl());
$report->addField($coverageTreemapField);
Notifications¶
atoum est capable de vous prévenir lorsque les tests sont exécutés en utilisant plusieurs systèmes de notification : Growl, Mac OS X Notification Center, Libnotify.
Growl¶
Cette fonctionnalité nécessite la présence de l’exécutable growlnotify
. Pour vérifier s’il est disponible, utilisez la commande suivante :
$ which growlnotify
Vous aurez alors le chemin de l’exécutable ou alors le message growlnotify not found
s’il n’est pas installé.
Il suffit ensuite d’ajouter le code suivant à votre fichier de configuration :
<?php
$images = '/path/to/atoum/resources/images/logo';
$notifier = new \mageekguy\atoum\report\fields\runner\result\notifier\image\growl();
$notifier
->setSuccessImage($images . DIRECTORY_SEPARATOR . 'success.png')
->setFailureImage($images . DIRECTORY_SEPARATOR . 'failure.png')
;
$report = $script->AddDefaultReport();
$report->addField($notifier, array(atoum\runner::runStop));
Mac OS X Notification Center¶
Cette fonctionnalité nécessite la présence de l’exécutable terminal-notifier
. Pour vérifier s’il est disponible, utilisez la commande suivante :
$ which terminal-notifier
Vous aurez alors le chemin de l’exécutable ou alors le message terminal-notifier not found
s’il n’est pas installé.
Note
Rendez-vous sur la page Github du projet pour obtenir plus d’information sur l’installation de terminal-notifier
.
Il suffit ensuite d’ajouter le code suivant à votre fichier de configuration :
<?php
$notifier = new \mageekguy\atoum\report\fields\runner\result\notifier\terminal();
$report = $script->AddDefaultReport();
$report->addField($notifier, array(atoum\runner::runStop));
Sous OS X, vous avez la possibilité de définir une commande qui sera exécutée lorsque l’utilisateur cliquera sur la notification.
<?php
$coverage = new atoum\report\fields\runner\coverage\html(
'Code coverage',
$path = sys_get_temp_dir() . '/coverage_' . time()
);
$coverage->setRootUrl('file://' . $path);
$notifier = new \mageekguy\atoum\report\fields\runner\result\notifier\terminal();
$notifier->setCallbackCommand('open file://' . $path . '/index.html');
$report = $script->AddDefaultReport();
$report
->addField($coverage, array(atoum\runner::runStop))
->addField($notifier, array(atoum\runner::runStop))
;
L’exemple ci-dessus montre comment ouvrir le rapport de couverture du code lorsque l’utilisateur clique sur la notification.
Libnotify¶
Cette fonctionnalité nécessite la présence de l’exécutable notify-send
. Pour vérifier s’il est disponible, utilisez la commande suivante :
$ which notify-send
Vous aurez alors le chemin de l’exécutable ou alors le message notify-send not found
s’il n’est pas installé.
Il suffit ensuite d’ajouter le code suivant à votre fichier de configuration :
<?php
$images = '/path/to/atoum/resources/images/logo';
$notifier = new \mageekguy\atoum\report\fields\runner\result\notifier\image\libnotify();
$notifier
->setSuccessImage($images . DIRECTORY_SEPARATOR . 'success.png')
->setFailureImage($images . DIRECTORY_SEPARATOR . 'failure.png')
;
$report = $script->AddDefaultReport();
$report->addField($notifier, array(atoum\runner::runStop));
Configuration du test¶
De nombreuses possibilités sont disponibles pour configurer comment atoum va exécuter le test. Vous pouvez utiliser les arguments en ligne de commande ou le fichier de configuration. Un code simple valant une longue explication, l’exemple suivant devrait être explicite :
<?php
$testGenerator = new atoum\test\generator();
// répertoire contenant le test unitaire. (-d)
$testGenerator->setTestClassesDirectory(__DIR__ . '/test/units');
// le namespace du test unitaire.
$testGenerator->setTestClassNamespace('your\project\namespace\tests\units');
// le runner de votre test unitaire.
$testGenerator->setRunnerPath('path/to/your/tests/units/runner.php');
$script->getRunner()->setTestGenerator($testGenerator);
// ou
$runner->setTestGenerator($testGenerator);
Vous pouvez également définir le répertoire du test avec $runner->addTestsFromDirectory(path)
. atoum chargera toutes les classes qui puissent être testées présentes dans ce dossier tout comme vous pouvez faire
avec l’argument en ligne de commande -d.
<?php
$runner->addTestsFromDirectory(__DIR__ . '/test/units');
Fichier de bootstrap¶
atoum autorise la définition d’un fichier de bootstrap
qui sera exécuté avant chaque méthode de test et qui permet donc d’initialiser l’environnement d’exécution des tests.
Le nom par défaut du fichier est .bootstrap.atoum.php
, atoum chargera le fichier automatiquement, si celui-ci est situé dans le répertoire courant. Vous pouvez le définir en cli avec -bf
ou --bootstrap-file
.
Il devient ainsi possible de définir, par exemple, de lire un fichier de configuration ou de réaliser toute autre opération nécessaire à la bonne exécution des tests.
La définition de ce fichier de bootstrap peut se faire de deux façons différentes, soit en ligne de commande, soit via un fichier de configuration.
$ ./bin/atoum -bf path/to/bootstrap/file
Note
Le fichier de bootstrap n’est pas un fichier de configuration et , n’as pas les même possibilités.
Dans un fichier de configuration, atoum est configurable via la variable $runner
, qui n’est pas définie dans un fichier de bootstrap
.
De plus, ils ne sont pas inclus au même moment, puisque le fichier de configuration est inclus par atoum avant le début de l’exécution des tests mais après le lancement des tests, alors que le fichier de bootstrap
, s’il est défini, est le tout premier fichier inclus par atoum proprement dit. Enfin, le fichier de bootstrap
peut permettre de ne pas avoir à inclure systématiquement le fichier scripts/runner.php
ou l’archive PHAR de atoum dans les classes de test.
Cependant, dans ce cas, il ne sera plus possible d’exécuter directement un fichier de test directement via l’exécutable PHP en ligne de commande.
Pour cela, il suffit d’inclure dans le fichier de bootstrap
le fichier scripts/runner.php
ou l’archive PHAR d’atoum et d’exécuter systématiquement les tests en ligne de commande via scripts/runner.php
ou l’archive PHAR.
Le fichier de bootstrap
doit donc au minimum contenir ceci :
<?php
// si l'archive PHAR est utilisée :
require_once path/to/atoum.phar;
// ou si vous voulez charger le $runner
// require_once path/atoum/scripts/runner.php
Amusons-nous avec atoum¶
Rapport¶
Les rapports de tests peuvent être décorés afin d’être plus agréables ou sympa à lire. Pour cela, dans le fichier de configuration d’atoum, ajoutez le code suivant
<?php
// Le fichier de configuration par défaut est .atoum.php
// ...
$stdout = new \mageekguy\atoum\writers\std\out;
$report = new \mageekguy\atoum\reports\realtime\nyancat;
$script->addReport($report->addWriter($stdout));
Vous pouvez aussi essayer \mageekguy\atoum\reports\realtime\santa
comme rapport ;)
Annotations¶
Dans cette section nous listons toutes les annotations utilisables avec atoum.
Annotation de classe¶
- @dataProvider
- @extensions
- @hasNotVoidMethods
- @hasVoidMethods
- @ignore
- @maxChildrenNumber
- @methodPrefix
- @namespace
- @php
- @tags
Annotation des méthodes¶
- @dataProvider
- @engine
- @extensions
- @ignore
- @isNotVoid
- @isVoid
- @php
- @tags
Data providers¶
Afin de permettre de tester efficacement vos classes, atoum fourni des data provider (fournisseur de données).
Un data provider est une méthode spécifique d’une classe de test chargée de générer des arguments pour une méthode de test, arguments qui seront utilisés par ladite méthode pour valider des assertions.
Si méthode de test testFoo
prend des arguments, mais qu’aucune annotation précisant le data provider n’est présente, atoum va automatiquement rechercher une méthode testFooDataProvider
.
Vous pouvez également définir manuellement le nom de la méthode du data provider grâce à l’annotation @dataProvider
à ajouter à la méthode de test :
<?php
class calculator extends atoum
{
/**
* @dataProvider sumDataProvider
*/
public function testSum($a, $b)
{
$this
->if($calculator = new project\calculator())
->then
->integer($calculator->sum($a, $b))->isEqualTo($a + $b)
;
}
// ...
}
Bien évidemment, il faut penser a définir les arguments de la méthode de test qui vont recevoir les données retournées par le data provider. Dans le cas contraire, atoum va retourner des erreurs lors de l’exécution des tests.
Un data provider est une méthode protégée qui retourne un tableau ou un itérateur qui contient de simples valeurs :
<?php
class calculator extends atoum
{
// ...
// Fourni des données pour testSum().
protected function sumDataProvider()
{
return array(
array( 1, 1),
array( 1, 2),
array(-1, 1),
array(-1, 2),
);
}
}
Lors de l’exécution des test, atoum va appeler la méthode testSum()
avec les arguments (1, 1)
, (1, 2)
, (-1, 1)
et (-1, 2)
, tels que retournés par la méthode sumDataProvider()
.
Avertissement
L’isolation des tests ne sera pas utilisée dans ce cas d’utilisation, ce qui signifie que les appels successifs à la méthode testSum()
seront exécutés dans le même processus PHP.
Data provider en tant que closure¶
Vous pouvez également utiliser une closure pour définir un data provider au lieu d’une annotation. Dans votre méthode beforeTestMethod, vous pouvez utiliser l’exemple suivant pour définir une closure :
<?php
class calculator extends atoum
{
// ...
public function beforeTestMethod($method)
{
if ($method == 'testSum')
{
$this->setDataProvider($method, function() {
return array(
array( 1, 1),
array( 1, 2),
array(-1, 1),
array(-1, 2),
);
});
}
}
}
Data provider injecté dans les méthode de test¶
Il y a aussi, une injection de bouchon dans les paramètres de la méthode de test. Prenons un exemple simple :
<?php
class cachingIterator extends atoum
{
public function test__construct()
{
$this
->given($iterator = new \mock\iterator())
->then
->object($this->newTestedInstance($iterator))
;
}
}
Vous pouvez l’écrire ainsi :
<?php
class cachingIterator extends atoum
{
public function test__construct(\iterator $iterator)
{
$this
->object($this->newTestedInstance($iterator))
;
}
}
Dans ce cas, pas besoin de data provider. Cependant, si vous désirez changer le comportement de vos bouchons, cela requiert l’utilisation de beforeTestMethod.
<?php
class cachingIterator extends atoum
{
public function test__construct(\iterator $iterator)
{
$this
->object($this->newTestedInstance($iterator))
;
}
public function beforeTestMethod($method)
{
// rend le controlleur orphelin pour le prochain mock généré, ici $iterator
$this->mockGenerator->orphanize('__construct');
}
}
PHP Extensions¶
Certains des tests peuvent requérir une ou plusieurs extensions PHP. atoum permet de définir cela directement à travers une annotation @extensions
. Après l’annotation @extensions
, ajouter simplement le nom d’une ou plusieurs extensions, séparés par une virgule.
<?php
namespace vendor\project\tests\units;
class foo extends \atoum
{
/**
* @extensions intl
*/
public function testBar()
{
// ...
}
}
Le test ne sera exécuté que si l’extension intl est présente. Dans le cas contraire, le test sera passé et le message suivant sera affiché.
vendor\project\tests\units\foo::testBar(): PHP extension 'intl' is not loaded
Note
Par défaut, le test est validé lorsqu’il a été passé. Mais vous pouvez utiliser –fail-if-skipped-methods l’option de la ligne de commande afin de faire échouer les tests passés.
PHP Version¶
Certains de vos tests peuvent requérir une version spécifique de PHP pour fonctionner (par exemple, pour certains tests ne fonctionnant qu’avec PHP 7). Dire à atoum qu’un test requiert une version spécifique de PHP s’effectue au travers de l’annotation @php
.
Par défaut, sans fournir d’opérateur, le test ne sera exécuté que si la version de PHP est supérieure ou égale à la version du tag :
class testedClassname extends atoum\test
{
/**
* @php 7.0
*/
public function testMethod()
{
// contenu du test
}
}
Dans cette exemple, le test ne sera exécuté que si la version de PHP est supérieure ou égale à PHP 7.0. Dans le cas contraire, le test sera passé et le message suivant sera affiché :
vendor\project\tests\units\foo::testBar(): PHP version 5.5.9-1ubuntu4.5 is not >= to 7.0
Note
Par défaut, le test est considéré valide lorsqu’il est passé. Mais vous pouvez utiliser –fail-if-skipped-methods l’option de la ligne de commande afin de faire échouer les tests passés.
En interne, atoum utilise le comparateur de version de PHP pour effectuer la comparaison.
Vous n’êtes pas limité à l’opérateur égal ou supérieur. Vous pouvez passer tout les opérateurs acceptés par version_compare.
Par exemple :
class testedClassname extends atoum\test
{
/**
* @php < 5.4
*/
public function testMethod()
{
// contenu du test
}
}
Va passer le test si la version de PHP est supérieure ou égale à PHP 5.4
vendor\project\tests\units\foo::testBar(): PHP version 5.5.9-1ubuntu4.5 is not < to 5.4
Vous pouvez aussi utiliser de multiples conditions, avec l’annotation @php
. Par exemple :
class testedClassname extends atoum\test
{
/**
* @php >= 5.4
* @php <= 7.0
*/
public function testMethod()
{
// contenu du test
}
}
Option de la ligne de commande¶
La plupart des options existent sous deux formes, une courte de 1 à 6 caractères et une longue, plus explicative. Les deux formes différentes font exactement la même chose et peuvent être utilisés indifféremment.
Certaines options acceptent plusieurs valeurs :
$ ./bin/atoum -f tests/units/MyFirstTest.php tests/units/MySecondTest.php
Note
Si vous utilisez une option plusieurs fois, seul la dernière servira.
# Ne test que MySecondTest.php
$ ./bin/atoum -f MyFirstTest.php -f MySecondTest.php
# Ne test que MyThirdTest.php et MyFourthTest.php
$ ./bin/atoum -f MyFirstTest.php MySecondTest.php -f MyThirdTest.php MyFourthTest.php
Configuration & bootstrap¶
-af <file> / –autoloader-file <file>¶
Cette option vous permet de spécifier le chemin du fichier d’autoloader.
$ ./bin/atoum -af /path/to/autloader.php
$ ./bin/atoum --autoloader-file /path/to/autoloader.php
-bf <file> / –bootstrap-file <file>¶
Cette option vous permet de spécifier le chemin du fichier de bootstrap.
$ ./bin/atoum -bf /path/to/bootstrap.php
$ ./bin/atoum --bootstrap-file /path/to/bootstrap.php
-c <file> / –configuration <file>¶
Cette option vous permet de spécifier le chemin vers le fichier de configuration à utiliser pour lancer les tests.
$ ./bin/atoum -c config/atoum.php
$ ./bin/atoum --configuration tests/units/conf/coverage.php
-xc, –xdebug-config¶
Cette option vous permet de spécifié la variable XDEBUG_CONFIG. Ceci peux aussi être configurer avec $runner->setXdebugConfig().
Filtrage¶
-d <directories> / –directories <directories>¶
Cette option vous permet de spécifier le répertoire des test à exécuter. Vous pouvez aussi le configurer.
$ ./bin/atoum -d tests/units/db/
$ ./bin/atoum --directories tests/units/db/ tests/units/entities/
-f <files> / –files <files>¶
Cette option vous permet de spécifier le ou les fichiers de tests à lancer.
$ ./bin/atoum -f tests/units/db/mysql.php
$ ./bin/atoum --files tests/units/db/mysql.php tests/units/db/pgsql.php
-g <pattern> / –glob <pattern>¶
Cette option vous permet de spécifier les fichiers de tests à lancer en fonction d’un schéma.
$ ./bin/atoum -g ???
$ ./bin/atoum --glob ???
-m <class::method> / –methods <class::methods>¶
Cette option vous permet de filtrer les classes et les méthodes à lancer.
# lance uniquement la méthode testMyMethod de la classe vendor\\project\\test\\units\\myClass
$ ./bin/atoum -m vendor\\project\\test\\units\\myClass::testMyMethod
$ ./bin/atoum --methods vendor\\project\\test\\units\\myClass::testMyMethod
# lance toutes les méthodes de test de la classe vendor\\project\\test\\units\\myClass
$ ./bin/atoum -m vendor\\project\\test\\units\\myClass::*
$ ./bin/atoum --methods vendor\\project\\test\\units\\myClass::*
# lance uniquement les méthodes testMyMethod de toutes les classes de test
$ ./bin/atoum -m *::testMyMethod
$ ./bin/atoum --methods *::testMyMethod
Note
Reportez-vous à la section sur les filtres par Une classe ou une méthode pour avoir plus d’informations.
-ns <namespaces> / –namespaces <namespaces>¶
Cette option vous permet de filtrer les classes et les méthodes en fonction des espaces de noms.
$ ./bin/atoum -ns mageekguy\\atoum\\tests\\units\\asserters
$ ./bin/atoum --namespaces mageekguy\\atoum\\tests\\units\\asserters
Note
Reportez-vous à la section sur les filtres Par espace de noms pour avoir plus d’informations.
-t <tags> / –tags <tags>¶
Cette option vous permet de filtrer les classes et les méthodes à lancer en fonction des tags.
$ ./bin/atoum -t OneTag
$ ./bin/atoum --tags OneTag TwoTag
Note
Reportez-vous à la section sur les filtres par Tags pour avoir plus d’informations.
–test-all¶
Cette option vous permet de lancer les tests se trouvant dans les répertoires définis dans le fichier de configuration via $script->addTestAllDirectory('path/to/directory')
.
$ ./bin/atoum --test-all
–test-it¶
Cette option vous permet de lancer les tests unitaires d’atoum pour vérifier qu’il fonctionne parfaitement sur votre serveur. Vous pouvez aussi le configurer avec $script->testIt();
.
$ ./bin/atoum --test-it
-tfe <extensions> / –test-file-extensions <extensions>¶
Cette option vous permet de spécifier le ou les extensions des fichiers de tests à lancer.
$ ./bin/atoum -tfe phpt
$ ./bin/atoum --test-file-extensions phpt php5t
Débugage & boucle¶
–debug¶
Cette option vous permet d’activer le mode debug
$ ./bin/atoum --debug
Note
Reportez-vous à la section sur le Débogage des scénarios de test pour avoir plus d’informations.
-l / –loop¶
Cette option vous permet d’activer le mode loop d’atoum.
$ ./bin/atoum -l
$ ./bin/atoum --loop
Note
Reportez-vous à la section sur le Mode répétition pour avoir plus d’informations.
–disable-loop-mode¶
Cette option vous permet de désactivé le mode loop. Ceci permet d’écraser un mode loop activé via le fichier de configuration.
Couverture & rapports¶
-drt <string> / –default-report-title <string>¶
Cette option permet de spécifier le titre par défaut du rapport d’atoum.
$ ./bin/atoum -drt Title
$ ./bin/atoum --default-report-title "My Title"
Note
Si le titre comporte des espaces, il faut obligatoirement l’entourer de guillemets.
-ebpc, –enable-branch-and-path-coverage¶
Cette option active la couverture sur les branches et chemin. Vous pouvez aussi le faire au travers de la configuration.
$ ./bin/atoum -ebpc
$ ./bin/atoum --enable-branch-and-path-coverage
-ft / –force-terminal¶
Cette option vous permet de forcer la sortie vers le terminal.
$ ./bin/atoum -ft
$ ./bin/atoum --force-terminal
-sf <file> / –score-file <file>¶
Cette option vous permet de spécifier le chemin vers le fichier des résultats créé par atoum.
$ ./bin/atoum -sf /path/to/atoum.score
$ ./bin/atoum --score-file /path/to/atoum.score
-ncc / –no-code-coverage¶
Cette option vous permet de désactiver la génération du rapport de la couverture de code.
$ ./bin/atoum -ncc
$ ./bin/atoum --no-code-coverage
-nccfc <classes> / –no-code-coverage-for-classes <classes>¶
Cette option vous permet de désactiver la génération du rapport de couverture de code pour un ou plusieurs classes.
$ ./bin/atoum -nccfc vendor\\project\\db\\mysql
$ ./bin/atoum --no-code-coverage-for-classes vendor\\project\\db\\mysql vendor\\project\\db\\pgsql
Note
Il est important de doubler chaque backslash pour éviter qu’ils soient interprétés par le shell.
-nccfns <namespaces> / –no-code-coverage-for-namespaces <namespaces>¶
Cette option vous permet de désactiver la génération du rapport de couverture de code pour un ou plusieurs namespaces.
$ ./bin/atoum -nccfns vendor\\outside\\lib
$ ./bin/atoum --no-code-coverage-for-namespaces vendor\\outside\\lib1 vendor\\outside\\lib2
Note
Il est important de doubler chaque backslash pour éviter qu’ils soient interprétés par le shell.
-nccid <directories> / –no-code-coverage-in-directories <directories>¶
Cette option vous permet de désactiver la génération du rapport de couverture de code pour un ou plusieurs répertoires.
$ ./bin/atoum -nccid /path/to/exclude
$ ./bin/atoum --no-code-coverage-in-directories /path/to/exclude/1 /path/to/exclude/2
-nccfm <method> / –no-code-coverage-for-methods <method>¶
Cette option vous permet de désactiver la génération du rapport de couverture de code pour une ou plusieurs méthodes.
$ ./bin/atoum -nccfm foo\\test\\units\\myClass::testMyMethod foo\\test\\units\\myClassToo::testMyMethod
$ ./bin/atoum --no-code-coverage-for-methods foo\\test\\units\\myClass::testMyMethod foo\\test\\units\\myClassToo::testMyMethod
-udr / –use-dot-report¶
Cette option vous permet d’afficher uniquement la progression de l’exécution avec des points.
$ bin/atoum -udr
$ bin/atoum --use-dot-report
............................................................ [60/65]
..... [65/65]
Success (1 test, 65/65 methods, 0 void method, 0 skipped method, 872 assertions)!
-ulr / –use-light-report¶
Cette option vous permet d’alléger la sortie généré par atoum.
$ ./bin/atoum -ulr
$ ./bin/atoum --use-light-report
[SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS>][ 59/1141]
[SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS>][ 118/1141]
[SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS>][ 177/1141]
[SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS>][ 236/1141]
[SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS>][ 295/1141]
[SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS>][ 354/1141]
[SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS>][ 413/1141]
[SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS>][ 472/1141]
[SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS>][ 531/1141]
[SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS>][ 590/1141]
[SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS>][ 649/1141]
[SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS>][ 708/1141]
[SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS>][ 767/1141]
[SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS>][ 826/1141]
[SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS>][ 885/1141]
[SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS>][ 944/1141]
[SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS>][1003/1141]
[SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS>][1062/1141]
[SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS>][1121/1141]
[SSSSSSSSSSSSSSSSSSSS________________________________________][1141/1141]
Success (154 tests, 1141/1141 methods, 0 void method, 0 skipped method, 16875 assertions) !
-utr / –use-tap-report¶
Cette option créer un rapport de type tap
$ ./bin/atoum -utr
$ ./bin/atoum --use-tap-report
Échec & succès¶
-fivm / –fail-if-void-methods¶
Cette option va faire échouer la suite de tests s’il y a au moins une méthode vide.
$ ./bin/atoum -fivm
$ ./bin/atoum --fail-if-void-methods
-fism / –fail-if-skipped-methods¶
Cette option va faire échouer la suite de tests s’il y a au moins une méthode ignorée
$ ./bin/atoum -fism
$ ./bin/atoum --fail-if-skipped-methods
Autres arguments¶
-mcn <integer> / –max-children-number <integer>¶
Cette option vous permet de définir le nombre maximum de processus lancés pour exécuter les tests.
$ ./bin/atoum -mcn 5
$ ./bin/atoum --max-children-number 3
-p <file> / –php <file>¶
Cette option vous permet de spécifier le chemin de l’exécutable php à utiliser pour lancer vos tests.
$ ./bin/atoum -p /usr/bin/php5
$ ./bin/atoum --php /usr/bin/php5
Par défaut, la valeur est recherchée parmi les valeurs suivantes (dans l’ordre) :
- constante PHP_BINARY
- variable d’environnement PHP_PEAR_PHP_BIN
- variable d’environnement PHPBIN
- constante PHP_BINDIR + “/php”
-h / –help¶
Cette option vous permet d’afficher la liste des options disponibles.
$ ./bin/atoum -h
$ ./bin/atoum --help
–init <directory>¶
Cette commande initialise quelques fichiers de configuration.
$ ./bin/atoum --init path/to/configuration/directory
-v / –version¶
Cette option vous permet d’afficher la version courante d’atoum.
$ ./bin/atoum -v
$ ./bin/atoum --version
atoum version DEVELOPMENT by Frédéric Hardy (/path/to/atoum)
Nouveau dans la version 3.3.0: Ajout du dot report
Cookbook¶
Changer l’espace de nom par défaut¶
Au début de l’exécution d’une classe de test, atoum calcule le nom de la classe testée. Pour cela, par défaut, il remplace dans le nom de la classe de test l’expression régulière #(?:^|\\\)tests?\\\units?\\#i
par le caractère \
.
Ainsi, si la classe de test porte le nom vendor\project\tests\units\foo
, il en déduira que la classe testée porte le nom vendor\project\foo
. Cependant, il peut être nécessaire que l’espace de nom des classes de test ne corresponde pas à cette expression régulière, et dans ce cas, atoum s’arrête alors avec le message d’erreur suivant :
> exception 'mageekguy\atoum\exceptions\runtime' with message 'Test class 'project\vendor\my\tests\foo' is not in a namespace which match pattern '#(?:^|\\)ests?\\unit?s\#i'' in /path/to/unit/tests/foo.php
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Il faut donc modifier l’expression régulière utilisée, ceci est possible de plusieurs manières. Le plus simple est de faire appel à l’annotation @namespace
appliquée à la classe de test, de la manière suivante :
<?php
namespace vendor\project\my\tests;
require_once __DIR__ . '/atoum.phar';
use mageekguy\atoum;
/**
* @namespace \my\tests
*/
abstract class aClass extends atoum
{
public function testBar()
{
/* ... */
}
}
Cette méthode est simple et rapide à mettre en œuvre, mais elle présente l’inconvénient de devoir être répétée dans chaque classe de test, ce qui peut compliquer leur maintenance en cas de modification de leur espace de nom. L’alternative consiste à faire appel à la méthode atoum\test::setTestNamespace()
dans le constructeur de la classe, de cette manière :
<?php
namespace vendor\project\my\tests;
require_once __DIR__ . '/atoum.phar';
use mageekguy\atoum;
abstract class aClass extends atoum
{
public function __construct(score $score = null, locale $locale = null, adapter $adapter = null)
{
$this->setTestNamespace('\\my\\tests');
parent::__construct($score, $locale, $adapter);
}
public function testBar()
{
/* ... */
}
}
La méthode atoum\test::setTestNamespace()
accepte en effet un unique argument qui doit être l’expression régulière correspondant à l’espace de nom de votre classe de test. Et pour ne pas avoir à répéter l’appel à cette méthode dans chaque classe de test, il suffit de le faire une bonne fois pour toutes dans une classe abstraite de la manière suivante :
<?php
namespace vendor\project\my\tests;
require_once __DIR__ . '/atoum.phar';
use mageekguy\atoum;
abstract class Test extends atoum
{
public function __construct(score $score = null, locale $locale = null, adapter $adapter = null)
{
$this->setTestNamespace('\\my\\tests');
parent::__construct($score, $locale, $adapter);
}
}
Ainsi, vous n’aurez plus qu’à faire dériver vos classes de tests unitaires de cette classe abstraite :
<?php
namespace vendor\project\my\tests\modules;
require_once __DIR__ . '/atoum.phar';
use mageekguy\atoum;
use vendor\project\my\tests;
class aModule extends tests\Test
{
public function testDoSomething()
{
/* ... */
}
}
En cas de modification de l’espace de nommage réservé aux tests unitaires, il ne sera donc nécessaire de ne modifier que la classe abstraite.
De plus, il n’est pas obligatoire d’utiliser une expression régulière, que ce soit au niveau de l’annotation @namespace
ou de la méthode atoum\test::setTestNamespace()
, et une simple chaîne de caractères peut également fonctionner.
En effet, atoum fait appel par défaut à une expression régulière afin que son utilisateur puisse utiliser par défaut un large panel d’espaces de nom sans avoir besoin de le configurer à ce niveau. Cela lui permet donc d’accepter par exemple sans configuration particulière les espaces de nomsuivants :
test\unit\
Test\Unit\
tests\units\
Tests\Units\
TEST\UNIT\
Cependant, en règle général, l’espace de nom utilisé pour les classes de test est fixe et il n’est donc pas nécessaire de recourir à une expression régulière si celle par défaut ne convient pas. Dans notre cas, elle pourrait être remplacée par la chaîne de caractères my\tests
, par exemple grâce à l’annotation @namespace
:
<?php
namespace vendor\project\my\tests;
require_once __DIR__ . '/atoum.phar';
use mageekguy\atoum;
/**
* @namespace \my\tests\
*/
abstract class aClass extends atoum
{
public function testBar()
{
/* ... */
}
}
Test d’un singleton¶
Pour tester si une méthode retourne bien systématiquement la même instance d’un objet, vérifiez que deux appels successifs à la méthode testée sont bien identiques.
<?php
$this
->object(\Singleton::getInstance())
->isInstanceOf('Singleton')
->isIdenticalTo(\Singleton::getInstance())
;
Hook git¶
Une bonne pratique, lorsqu’on utilise un logiciel de gestion de versions, est de ne jamais ajouter à un dépôt du code non fonctionnel, afin de pouvoir récupérer une version propre et utilisable du code à tout moment et à n’importe quel endroit de l’historique du dépôt.
Cela implique donc, entre autres, que les tests unitaires doivent passer dans leur intégralité avant que les fichiers créés ou modifiés soient ajoutés au dépôt et, en conséquence, le développeur est censé exécuter les tests unitaires avant d’intégrer son code dans le dépôt.
Cependant, dans les faits, il est très facile pour le développeur d’omettre cette étape, et votre dépôt peut donc contenir à plus ou moins brève échéance du code ne respectant pas les contraintes imposées par les tests unitaires.
Heureusement, les logiciels de gestion de versions en général et Git en particulier disposent d’un mécanisme, connu sous le nom de hook de pré-commit permettant d’exécuter automatiquement des tâches lors de l’ajout de code dans un dépôt.
L’installation d’un hook de pré-commit est très simple et se déroule en deux étapes.
Étape 1 : Création du script à exécuter¶
Lors de l’ajout de code à un dépôt, Git recherche le fichier .git/hook/pre-commit
à la racine du dépôt et l’exécute s’il existe et qu’il dispose des droits nécessaires.
Pour mettre en place le hook, il vous faut donc créer le fichier .git/hook/pre-commit
et y ajouter le code suivant :
Le code ci-dessous suppose que vos tests unitaires sont dans des fichiers ayant l’extension .php
et dans des répertoires dont le chemin contient /Tests/Units/
. Si ce n’est pas votre cas, vous devrez modifier le script suivant votre contexte.
Note
Dans l’exemple ci-dessus, les fichiers de test doivent inclure atoum pour que le hook fonctionne.
Les tests étant exécutés très rapidement avec atoum, on peut donc lancer l’ensemble des tests unitaires avant chaque commit avec un hook comme celui-ci :
#!/bin/sh
./bin/atoum -d tests/
Étape 2 : Ajout des droits d’exécution¶
Pour être utilisable par Git, le fichier .git/hook/pre-commit
doit être rendu exécutable à l’aide de la commande suivante, exécutée en ligne de commande à partir du répertoire de votre dépôt :
$ chmod u+x `.git/hook/pre-commit`
À partir de cet instant, les tests unitaires contenus dans les répertoires dont le chemin contient /Tests/Units/
seront lancés automatiquement lorsque vous effectuerez la commande git commit
, si des fichiers ayant l’extension .php
ont été modifiés.
Et si d’aventure un test ne passe pas, les fichiers ne seront pas ajoutés au dépôt. Il vous faudra alors effectuer les corrections nécessaires, utiliser la commande git add
sur les fichiers modifiés et utiliser à nouveau git commit
.
Utilisation dans behat¶
Les asserters d’atoum sont très facilement utilisables hors de vos tests unitaires classiques. Il vous suffit d’importer la classe mageekguyatoumasserter en n’oubliant pas d’assurer le chargement des classes nécessaires (atoum fournit une classe d’autoload disponible dans classes/autoloader.php). L’exemple suivant illustre cette utilisation des asserters atoum à l’intérieur de vos steps Behat.
Installation¶
Installez simplement atoum et Behat dans votre projet via pear, git clone, zip… Voici un exemple avec le gestionnaire de dépendances Composer :
"require-dev": {
"behat/behat": "2.4@stable",
"atoum/atoum": "~2.5"
}
Il est évidemment nécessaire de remettre à jour vos dépendances composer en lançant la commande :
$ php composer.phar update
Configuration¶
Comme mentionné en introduction, il suffit d’importer la classe d’asserter et d’assurer le chargement des classes d’atoum. Pour Behat, la configuration des asserters s’effectue dans votre classe FeatureContext.php (située par défaut dans le répertoire /RACINE DE VOTRE PROJET/features/bootstrap/).
<?php
use Behat\Behat\Context\ClosuredContextInterface,
Behat\Behat\Context\TranslatedContextInterface,
Behat\Behat\Context\BehatContext,
Behat\Behat\Exception\PendingException,
Behat\Behat\Context\Step;
use Behat\Gherkin\Node\PyStringNode,
Behat\Gherkin\Node\TableNode;
use atoum\asserter; // <- atoum asserter
require_once __DIR__ . '/../../vendor/atoum/atoum/classes/autoloader.php'; // <- autoload
class FeatureContext extends BehatContext
{
private $assert;
public function __construct(array $parameters)
{
$this->assert = new asserter\generator();
}
}
Utilisation¶
Après ces 2 étapes particulièrement triviales, vos steps peuvent s’enrichir des asserters atoum :
<?php
// ...
class FeatureContext extends BehatContext
{//...
/**
* @Then /^I should get a good response using my favorite "([^"]*)"$/
*/
public function goodResponse($contentType)
{
$this->assert
->integer($response->getStatusCode())
->isIdenticalTo(200)
->string($response->getHeader('Content-Type'))
->isIdenticalTo($contentType);
}
}
Encore une fois, ceci n’est qu’un exemple spécifique à Behat mais il reste valable pour tous les besoins d’utilisation des asserters d’atoum hors contexte initial.
Utilisation dans des outils d’intégration continue (CI)¶
Utilisation dans Jenkins (ou Hudson)¶
Il est très simple d’intégrer les résultats de tests atoum à Jenkins (ou Hudson) en tant que résultats xUnit.
Étape 1 : Ajout d’un rapport xUnit à la configuration atoum¶
Comme pour les autres rapports de couverture, vous pouvez définir des rapports spécifiques dans la configuration.
Si vous n’avez pas de fichier de configuration¶
Si vous ne disposez pas encore d’un fichier de configuration pour atoum, nous vous recommandons d’extraire le répertoire ressource d’atoum dans celui de votre choix à l’aide de la commande suivante :
- Si vous utilisez l’archive Phar d’atoum :
$ php atoum.phar --extractRessourcesTo /tmp/atoum-src
$ cp /tmp/atoum-src/resources/configurations/runner/xunit.php.dist /mon/projet/.atoum.php
- Si vous utilisez les sources d’atoum :
$ cp /chemin/vers/atoum/resources/configurations/runner/xunit.php.dist /mon/projet/.atoum.php
- Vous pouvez également copier le fichier directement depuis le dépôt Github
Il ne vous reste plus qu’à éditer ce fichier pour choisir l’emplacement où atoum génèrera le rapport xUnit. Ce fichier est prêt à l’emploi, avec lui, vous conservez le rapport par défaut d’atoum et vous obtiendrez un rapport xUnit à la suite de chaque lancement des tests.
Si vous avez déjà un fichier de configuration¶
Si vous disposez déjà d’un fichier de configuration, il vous suffit d’y ajouter les lignes suivantes :
<?php
//...
/*
* Xunit report
*/
$xunit = new atoum\reports\asynchronous\xunit();
$runner->addReport($xunit);
/*
* Xunit writer
*/
$writer = new atoum\writers\file('/chemin/vers/le/rapport/atoum.xunit.xml');
$xunit->addWriter($writer);
Étape 2 : Tester la configuration¶
Pour tester cette configuration, il suffit de lancer atoum en lui précisant le fichier de configuration que vous souhaitez utiliser :
$ ./bin/atoum -d /chemin/vers/les/tests/units -c /chemin/vers/la/configuration.php
Note
Si vous avez nommé votre fichier de configuration .atoum.php
, atoum le chargera automatiquement. Le paramètre -c
est donc optionnel dans ce cas.
Pour qu’atoum charge automatiquement ce fichier, vous devrez lancer les tests à partir du dossier où se trouve le fichier .atoum.php
ou d’un de ses enfants.
À la fin de l’exécution des tests, vous devriez voir le rapport xUnit dans le répertoire indiqué dans le fichier de configuration.
Étape 3 : Lancement des tests via Jenkins (ou Hudson)¶
Il existe pour cela plusieurs possibilités selon la façon dont vous construisez votre projet :
- Si vous utilisez un script, il vous suffit d’y ajouter la commande précédente.
- Si vous passez par un utilitaire tel que phing ou ant, il suffit d’ajouter une tâche exec :
<target name="unitTests">
<exec executable="/usr/bin/php" failonerror="yes" failifexecutionfails="yes">
<arg line="/path/to/atoum.phar -p /path/to/php -d /path/to/test/folder -c /path/to/atoumConfig.php" />
</exec>
</target>
Vous noterez l’ajout du paramètre -p /chemin/vers/php
qui permet d’indiquer à atoum le chemin vers le binaire PHP qu’il doit utiliser pour exécuter les tests unitaires.
Étape 4 : Publier le rapport avec Jenkins (ou Hudson)¶
Il suffit tout simplement d’activer la publication des rapports au format JUnit ou xUnit, en fonction du plug-in que vous utilisez, en lui indiquant le chemin d’accès au fichier généré par atoum.
Utilisation avec Travis-ci¶
Il est assez simple d’utiliser atoum dans l’outil qu’est Travis-CI. En effet, l’ensemble des étapes est indiqué dans la documentation de travis : * Créer votre fichier .travis.yml dans votre projet; * Ajoutez-y les deux lignes suivantes :
before_script: wget http://downloads.atoum.org/nightly/atoum.phar
script: php atoum.phar
Voici un exemple de fichier .travis.yml dont les tests présents dans le dossier tests seront exécuter.
language: php
php:
- 5.4
- 5.5
- 5.6
before_script: wget http://downloads.atoum.org/nightly/atoum.phar
script: php atoum.phar -d tests/
Utilisation avec Phing¶
La suite de tests de atoum peut facilement être exécutée au sein de votre configuration phing via l’intégration de la tâche phing/AtoumTask.php. Un exemple valide peut être trouvé dans le fichier resources/phing/build.xml.
Vous devez néanmoins enregistrer votre tâche personnalisée en utilisant taskdef , une tâche native de phing :
<taskdef name="atoum" classpath="vendor/atoum/atoum/resources/phing" classname="AtoumTask"/>
Ensuite vous pouvez l’utiliser à l’intérieur de l’une de vos étapes du fichier de build :
<target name="test">
<atoum
atoumautoloaderpath="vendor/atoum/atoum/classes/autoloader.php"
phppath="/usr/bin/php"
codecoverage="true"
codecoveragereportpath="reports/html/"
showcodecoverage="true"
showmissingcodecoverage="true"
maxchildren="5"
>
<fileset dir="tests/units/">
<include name="**/*.php"/>
</fileset>
</atoum>
</target>
Les chemins donnés dans cet exemple a été pris à partir d’une installation standard via composer. Tous les paramètres possibles sont définis ci-dessous, vous pouvez modifier les valeurs ou en omettre certains et hériter des valeurs par défaut. Il y a trois types de paramètres :
Configuration d’atoum¶
- bootstrap: fichier de bootstrap à inclure, exécuté avant chaque méthode de test
- default:
.bootstrap.atoum.php
- default:
- atoumpharpath: si atoum est utilisé au travers d’un phar, chemin vers celui-ci
- atoumautoloaderpath: fichier d’autoloader, le fichier est exécuté avant chaque méthode de test
- default:
.autoloader.atoum.php
- default:
- phppath: chemin vers l’exécutable
php
- maxchildren: nombre maximum de sous-process qui peuvent tourner simultanément
Flags¶
- codecoverage: active la couverture de code(uniquement si XDebug est disponible)
- default:
false
- default:
- showcodecoverage: montre le rapport de couverture de code
- default:
true
- default:
- showduration: montre la durée de l’exécution des tests
- default:
true
- default:
- showmemory: affiche la consommation mémoire
- default:
true
- default:
- showmissingcodecoverage: montre la couverture de code manquante
- default:
true
- default:
- showprogress: affiche la barre de progression de l’exécution des tests
- default:
true
- default:
- branchandpathcoverage: active la couverture de code sur les chemins et branches
- default:
false
- default:
- telemetry: active le rapport telemetry (l’extension atoum/reports-extension doit être installée)
- default:
false
- default:
Rapports¶
- codecoveragexunitpath: chemin vers le rapport xunit
- codecoveragecloverpath: chemin vers le rapport clover
- Couverture de code basic
- codecoveragereportpath: chemin vers le rapport html
- codecoveragereporturl: url dans le rapport HTML
- Couverture de code treemap:
- codecoveragetreemappath: chemin vers le rapport treemap
- codecoveragetreemapurl: url pour le treemap
- Couverture de code avancée
- codecoveragereportextensionpath: chemin vers le rapport html
- codecodecoveragereportextensionurl: url du rapport HTML
- Telemetry
- telemetryprojectname: nom du projet a envoyer à telemetry
Utilisation avec des frameworks¶
Utilisation avec ez Publish¶
Étape 1 : Installation d’atoum au sein d’eZ Publish¶
Le framework eZ Publish possède déjà un répertoire dédié aux tests, nommé logiquement tests. C’est donc dans ce répertoire que devra être placé l”archive PHAR d’atoum. Les fichiers de tests unitaires utilisant atoum seront quant à eux placés dans un sous-répertoire tests/atoum afin qu’ils ne soient pas en conflit avec l’existant.
Étape 2 : Création de la classe de test de base¶
Une classe de test basée sur atoum doit étendre la classe \mageekguy\atoum\test
. Toutefois, celle-ci ne tient pas compte des spécifications de eZ Publish. .
Il est donc nécessaire de définir une classe de test de base, dérivée de \mageekguy\atoum\test
, qui prendra en compte ces spécifités et donc dérivera l’ensemble des classes de tests unitaires. Pour cela, il suffit de définir la classe suivante dans le fichier tests\atoum\test.php
:
<?php
namespace ezp;
use mageekguy\atoum;
require_once __DIR__ . '/atoum.phar';
// Autoloading : eZ
require 'autoload.php';
if ( !ini_get( "date.timezone" ) )
{
date_default_timezone_set( "UTC" );
}
require_once( 'kernel/common/i18n.php' );
\eZContentLanguage::setCronjobMode();
/**
* @abstract
*/
abstract class test extends atoum\test
{
}
?>
Étape 3 : Création d’une classe de test¶
Par défaut, atoum demande à ce que les classes de tests unitaires soient dans un espace de noms contenant test(s)unit(s), afin de pouvoir déduire le nom de la classe testée. À titre d’exemple, l’espace de noms nomprojet sera utilisé dans ce qui suit. Pour plus de simplicité, il est de plus conseillé de calquer l’arborescence des classes de test sur celle des classes testées, afin de pouvoir localiser rapidement la classe de test d’une classe, et inversement.
<?php
namespace nomdeprojet\tests\units;
require_once '../test.php';
use ezp;
class cache extends ezp\test
{
public function testClass()
{
$this->assert->hasMethod('__construct');
}
}
Étapes 4 : Exécution des tests unitaires¶
Une fois une classe de test créée, il suffit d’exécuter en ligne de commande l’instruction ci-dessous pour lancer le test, en se plaçant à la racine du projet :
# php tests/atoum/atoum.phar -d tests/atoum/units
Merci Jérémy Poulain pour ce tutoriel.
Utilisation avec Symfony 2¶
Si vous souhaitez utiliser atoum au sein de vos projets Symfony, vous pouvez installer le Bundle AtoumBundle.
Si vous souhaitez installer et configurer atoum manuellement, voici comment faire.
Étape 1: installation d’atoum¶
Si vous utilisez Symfony 2.0, téléchargez l’archive PHAR et placez-la dans le répertoire vendor qui est à la racine de votre projet.
Si vous utilisez Symfony 2.1+, ajoutez atoum dans votre fichier composer.json.
Étape 2: création de la classe de test¶
Imaginons que nous voulions tester cet Entity:
<?php
// src/Acme/DemoBundle/Entity/Car.php
namespace Acme\DemoBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Acme\DemoBundle\Entity\Car
* @ORM\Table(name="car")
* @ORM\Entity(repositoryClass="Acme\DemoBundle\Entity\CarRepository")
*/
class Car
{
/**
* @var integer $id
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @var string $name
* @ORM\Column(name="name", type="string", length=255)
*/
private $name;
/**
* @var integer $max_speed
* @ORM\Column(name="max_speed", type="integer")
*/
private $max_speed;
}
Note
Pour plus d’informations sur la création d’Entity dans Symfony 2, référez vous au manuel officiel
Créez le répertoire Tests/Units dans votre Bundle (par exemple src/Acme/DemoBundle/Tests/Units). C’est dans ce répertoire que seront stockés tous les tests de ce Bundle.
Créez un fichier Test.php qui servira de base à tous les futurs tests de ce Bundle.
<?php
// src/Acme/DemoBundle/Tests/Units/Test.php
namespace Acme\DemoBundle\Tests\Units;
// On inclus et active le class loader
require_once __DIR__ . '/../../../../../vendor/symfony/symfony/src/Symfony/Component/ClassLoader/UniversalClassLoader.php';
$loader = new \Symfony\Component\ClassLoader\UniversalClassLoader();
$loader->registerNamespaces(
array(
'Symfony' => __DIR__ . '/../../../../../vendor/symfony/src',
'Acme\DemoBundle' => __DIR__ . '/../../../../../src'
)
);
$loader->register();
use mageekguy\atoum;
// Pour Symfony 2.0 uniquement !
require_once __DIR__ . '/../../../../../vendor/atoum.phar';
abstract class Test extends atoum
{
public function __construct(
adapter $adapter = null,
annotations\extractor $annotationExtractor = null,
asserter\generator $asserterGenerator = null,
test\assertion\manager $assertionManager = null,
\closure $reflectionClassFactory = null
)
{
$this->setTestNamespace('Tests\Units');
parent::__construct(
$adapter,
$annotationExtractor,
$asserterGenerator,
$assertionManager,
$reflectionClassFactory
);
}
}
Note
L’inclusion de l’archive PHAR d’atoum n’est nécessaire que pour Symfony 2.0. Supprimez cette ligne dans le cas où vous utilisez Symfony 2.1+.
Note
Par défaut, atoum utilise le namespace tests/units pour les tests. Or Symfony 2 et son class loader exige des majuscules au début des noms. Pour cette raison, nous changeons le namespace des tests grâce à la méthode setTestNamespace(“TestsUnits”).
Étape 3: écriture d’un test¶
Dans le répertoire Tests/Units, il vous suffit de recréer l’arborescence des classes que vous souhaitez tester (par exemple src/Acme/DemoBundle/Tests/Units/Entity/Car.php).
Créons notre fichier de test:
<?php
// src/Acme/DemoBundle/Tests/Units/Entity/Car.php
namespace Acme\DemoBundle\Tests\Units\Entity;
require_once __DIR__ . '/../Test.php';
use Acme\DemoBundle\Tests\Units\Test;
class Car extends Test
{
public function testGetName()
{
$this
->if($car = new \Acme\DemoBundle\Entity\Car())
->and($car->setName('Batmobile'))
->string($car->getName())
->isEqualTo('Batmobile')
->isNotEqualTo('De Lorean')
;
}
}
Étape 4: lancement des tests¶
Si vous utilisez Symfony 2.0:
# Lancement des tests d'un fichier
$ php vendor/atoum.phar -f src/Acme/DemoBundle/Tests/Units/Entity/Car.php
# Lancement de tous les tests du Bundle
$ php vendor/atoum.phar -d src/Acme/DemoBundle/Tests/Units
Si vous utilisez Symfony 2.1+:
# Lancement des tests d'un fichier
$ ./bin/atoum -f src/Acme/DemoBundle/Tests/Units/Entity/Car.php
# Lancement de tous les tests du Bundle
$ ./bin/atoum -d src/Acme/DemoBundle/Tests/Units
Note
Vous pouvez obtenir plus d’informations sur le lancement des tests dans le chapitre qui y est consacré.
Dans tous les cas, voilà ce que vous devriez obtenir:
> PHP path: /usr/bin/php
> PHP version:
> PHP 5.3.15 with Suhosin-Patch (cli) (built: Aug 24 2012 17:45:44)
===================================================================
> Copyright (c) 1997-2012 The PHP Group
=======================================
> Zend Engine v2.3.0, Copyright (c) 1998-2012 Zend Technologies
===============================================================
> with Xdebug v2.1.3, Copyright (c) 2002-2012, by Derick Rethans
====================================================================
> Acme\DemoBundle\Tests\Units\Entity\Car...
[S___________________________________________________________][1/1]
> Test duration: 0.01 second.
=============================
> Memory usage: 0.50 Mb.
========================
> Total test duration: 0.01 second.
> Total test memory usage: 0.50 Mb.
> Code coverage value: 42.86%
> Class Acme\DemoBundle\Entity\Car: 42.86%
==========================================
> Acme\DemoBundle\Entity\Car::getId(): 0.00%
--------------------------------------------
> Acme\DemoBundle\Entity\Car::setMaxSpeed(): 0.00%
--------------------------------------------------
> Acme\DemoBundle\Entity\Car::getMaxSpeed(): 0.00%
--------------------------------------------------
> Running duration: 0.24 second.
Success (1 test, 1/1 method, 0 skipped method, 4 assertions) !
Utilisation avec symfony 1.4¶
Si vous souhaitez utiliser atoum au sein de vos projets Symfony 1.4, vous pouvez installer le plugin sfAtoumPlugin. Celui-ci est disponible à l’adresse suivante: https://github.com/atoum/sfAtoumPlugin.
Installation¶
Il existe plusieurs méthodes d’installation du plugin dans votre projet :
- installation via composer
- installation via des submodules git
En utilisant composer¶
Ajouter ceci dans le composer.json :
"require" : {
"atoum/sfAtoumPlugin": "*"
},
Après avoir effectué un php composer.phar update
, le plugin devrait se trouver dans le dossier plugins et atoum dans un dossier vendor
.
Il faut ensuite activer le plugin dans le ProjectConfiguration et indiquer le chemin d’atoum.
<?php
sfConfig::set('sf_atoum_path', dirname(__FILE__) . '/../vendor/atoum/atoum');
if (sfConfig::get('sf_environment') != 'prod')
{
$this->enablePlugins('sfAtoumPlugin');
}
En utilisant des submodules git¶
Il faut tout d’abord ajouter atoum en tant que submodule :
$ git submodule add git://github.com/atoum/atoum.git lib/vendor/atoum
Puis ensuite ajouter le sfAtoumPlugin en tant que submodule :
$ git submodule add git://github.com/atoum/sfAtoumPlugin.git plugins/sfAtoumPlugin
Enfin, il faut activer le plugin dans le fichier ProjectConfiguration :
<?php
if (sfConfig::get('sf_environment') != 'prod')
{
$this->enablePlugins('sfAtoumPlugin');
}
Ecrire les tests¶
Les tests doivent inclure le fichier de bootstrap se trouvant dans le plugin :
<?php
require_once __DIR__ . '/../../../../plugins/sfAtoumPlugin/bootstrap/unit.php';
Lancer les tests¶
La commande symfony atoum:test
est disponible. Les tests peuvent alors se lancer de cette façon :
$ ./symfony atoum:test
Toutes les paramètres d’atoum sont disponibles.
Il est donc, par exemple, possible de passer un fichier de configuration comme ceci :
php symfony atoum:test -c config/atoum/hudson.php
Plugin symfony 1¶
Pour utiliser atoum au sein d’un projet symfony 1, un plug-in existe et est disponible à l’adresse suivante : https://github.com/atoum/sfAtoumPlugin.
Toutes les instructions pour son installation et son utilisation se trouvent dans le cookbook Utilisation avec symfony 1.4 ainsi que sur la page github.
Bundle Symfony 2¶
Pour utiliser atoum au sein d’un projet Symfony 2, le bundle AtoumBundle est disponible.
Toutes les instructions pour son installation et son utilisation se trouvent dans le cookbook Utilisation avec Symfony 2 ainsi que sur la page github.
Composant Zend Framework 2¶
Si vous souhaitez utiliser atoum au sein d’un projet Zend Framework 2, un composant existe et est disponible à l’adresse suivante.
Toutes les instructions pour son installation et son utilisation sont disponibles sur cette page.
Intégration d’atoum dans votre IDE¶
Sublime Text 2¶
Un plug-in pour SublimeText 2 permet l’exécution des tests unitaires par atoum et la visualisation du résultat sans quitter l’éditeur.
Les informations nécessaires à son installation et à sa configuration sont disponibles sur le blog de son auteur.
VIM¶
atoum est livré avec un plug-in facilitant son utilisation dans l’éditeur VIM.
Il permet d’exécuter les tests sans quitter VIM et d’obtenir le rapport correspondant dans une fenêtre de l’éditeur.
Il est alors possible de naviguer parmi les éventuelles erreurs, voire de se rendre à la ligne correspondant à une assertion ne passant pas à l’aide d’une simple combinaison de touches.
Installation du plug-in atoum pour VIM¶
Vous trouverez le fichier correspondant au plug-in, nommé atoum.vmb
, dans le répertoire resources/vim
.
Si vous utilisez l’archive PHAR, il faut extraire le fichier à l’aide de la commande suivante :
$ php atoum.phar --extractResourcesTo path/to/a/directory
Une fois l’extraction réalisée, le fichier atoum.vmb
correspondant au plug-in pour VIM sera dans le répertoire path/to/a/directory/resources/vim
.
Une fois en possession du fichier atoum.vmb
, il faut l’éditer à l’aide de VIM :
$ vim path/to/atoum.vmb
Il n’y a plus ensuite qu’à demander à VIM l’installation du plug-in à l’aide de la commande :
:source %
Utilisation du plug-in atoum pour VIM¶
Pour utiliser le plug-in, atoum doit évidemment être installé et vous devez être en train d’éditer un fichier contenant une classe de tests unitaires basée sur atoum.
Une fois dans cette configuration, la commande suivante lancera l’exécution des tests :
:Atoum
Les tests sont alors exécutés, et une fois qu’ils sont terminés, un rapport basé sur le fichier de configuration d’atoum qui se trouve dans le répertoire ftplugin/php/atoum.vim
de votre répertoire .vim
est généré dans une nouvelle fenêtre.
Évidemment, vous êtes libre de lier cette commande à la combinaison de touches de votre choix, en ajoutant par exemple la ligne suivante dans votre fichier .vimrc
:
nnoremap *.php <F12> :Atoum<CR>
L’utilisation de la touche F12
de votre clavier en mode normal appellera alors la commande :Atoum
.
Gestion des fichiers de configuration d’atoum¶
Vous pouvez indiquer un autre fichier de configuration pour atoum en ajoutant la ligne suivante à votre fichier .vimrc
:
call atoum#defineConfiguration('/path/to/project/directory', '/path/to/atoum/configuration/file', '.php')
La fonction atoum#defineConfiguration
permet en effet de définir le fichier de configuration à utiliser en fonction du répertoire où se trouve le fichier de tests unitaires.
Elle accepte pour cela trois arguments :
- un chemin d’accès vers le répertoire contenant les tests unitaires ;
- un chemin d’accès vers le fichier de configuration d’atoum devant être utilisé ;
- l’extension des fichiers de tests unitaires concernés.
Pour plus de détails sur l’utilisation du plug-in, une aide est disponible dans VIM à l’aide de la commande suivante :
:help atoum
Rapports de couverture pour vim¶
Vous pouvez configurer un rapport spécifique pour la couverture au sein de vim. Dans votre fichier de configuration atoum, définissez :
… code-block:: php
<?php use mageekguyatoum; $vimReport = new atoumreportsasynchronousvim(); $vimReport->addWriter($stdOutWriter); $runner->addReport($vimReport);
PhpStorm¶
atoum possède avec un plug-in officiel pour PHPStorm. Il vous aide, au quotidien, dans votre développement. Les principales fonctionnalités sont :
- Accès à la classe de test depuis la classe testée (raccourci : alt+shift+K)
- Accès à la classe testée depuis la de test (raccourcis : alt+shift+K)
- Execute tests inside PhpStorm (shortcut : alt+shift+M)
- Identification facile des fichiers de test via une icône spécifique
Installation¶
C’est simple à installer, pour cela il suffit de suivre les étapes suivantes :
- Ouvrir PHPStorm
- Aller dans Fichier -> Paramètres, cliquer sur Plugins
- Cliquer sur parcourir le répertoire
- Chercher atoum dans la liste, cliquer sur le bouton installation
- Redémarrer PHPStorm
Si vous avez besoin de plus d’information, il suffit de lire le repository du plugin.
Atom¶
atoum possède un plug-in officiel pour atom. Celui-ci vous aide dans plusieurs tâches :
- Un panneau avec tous les tests
- Exécuter tous les tests, dans un répertoire ou dans le répertoire courant
Installation¶
Il est simple d’installation, il suffit de suivre les étapes d’installation officiel ou les étapes suivantes :
- Ouvrir atom
- Aller dans Paramètres, cliquer sur Installation
- Chercher atoum dans la liste, cliquer sur le bouton installation
Si vous avez besoin de plus d’information, il suffit de lire le repository du package.
Ouvrir automatiquement les tests en échec¶
atoum est capable d’ouvrir automatiquement les fichiers des tests en échec à la fin de l’exécution. Plusieurs éditeurs sont actuellement supportés :
Pour utiliser cette fonctionnalité, vous devrez modifier le fichier de configuration d’atoum :
macvim¶
<?php
use
mageekguy\atoum,
mageekguy\atoum\report\fields\runner\failures\execute\macos
;
$stdOutWriter = new atoum\writers\std\out();
$cliReport = new atoum\reports\realtime\cli();
$cliReport->addWriter($stdOutWriter);
$cliReport->addField(new macos\macvim());
$runner->addReport($cliReport);
gvim¶
<?php
use
mageekguy\atoum,
mageekguy\atoum\report\fields\runner\failures\execute\unix
;
$stdOutWriter = new atoum\writers\std\out();
$cliReport = new atoum\reports\realtime\cli();
$cliReport->addWriter($stdOutWriter);
$cliReport->addField(new unix\gvim());
$runner->addReport($cliReport);
PhpStorm¶
Si vous travaillez sous Mac OS X, utilisez la configuration suivante :
<?php
use
mageekguy\atoum,
mageekguy\atoum\report\fields\runner\failures\execute\macos
;
$stdOutWriter = new atoum\writers\std\out();
$cliReport = new atoum\reports\realtime\cli();
$cliReport->addWriter($stdOutWriter);
$cliReport
// Si PhpStorm est installé dans /Applications
->addField(new macos\phpstorm())
// Si vous avez installé PhpStorm
// dans un dossier différent de /Applications
// ->addField(
// new macos\phpstorm(
// '/path/to/PhpStorm.app/Contents/MacOS/webide'
// )
// )
;
$runner->addReport($cliReport);
Dans un environnement Unix, utilisez la configuration suivante :
<?php
use
mageekguy\atoum,
mageekguy\atoum\report\fields\runner\failures\execute\unix
;
$stdOutWriter = new atoum\writers\std\out();
$cliReport = new atoum\reports\realtime\cli();
$cliReport->addWriter($stdOutWriter);
$cliReport
->addField(
new unix\phpstorm('/chemin/vers/PhpStorm/bin/phpstorm.sh')
)
;
$runner->addReport($cliReport);
gedit¶
<?php
use
mageekguy\atoum,
mageekguy\atoum\report\fields\runner\failures\execute\unix
;
$stdOutWriter = new atoum\writers\std\out();
$cliReport = new atoum\reports\realtime\cli();
$cliReport->addWriter($stdOutWriter);
$cliReport->addField(new unix\gedit());
$runner->addReport($cliReport);
Questions Fréquentes¶
Si vous avec une erreur inconnue, vérifier si vous utiliser un error_log ?¶
Si vous utilisez error_log, vous rencontrerez une erreur « Error UNKNOWN in » de atoum. Pour éviter cela, utiliser un mock d’une fonction native de error_log
<?php
namespace Foo
{
class TestErrorLog
{
public function runErrorLog()
{
error_log('message');
return true;
}
}
}
namespace Foo\test\unit
{
class TestErrorLog extends \atoum
{
public function testRunErrorLog()
{
$this->function->error_log = true;
$this->newTestedInstance;
$this->boolean($this->testedInstance->runErrorLog())->isTrue;
$this->function('error_log')->wasCalled()->once();
}
}
}
atoum s’est-il toujours appelé atoum ?¶
Non, au début, atoum était nommé ogo. Lorsque vous écrivez PHP sur un clavier azerty, puis que vous décalé d’une touche vers la gauche, vous écrivez ogo.
Quelle est la licence de atoum ?¶
atoum est distribué sous la licence BSD-3-Clause. Regarder le fichier de LICENSE embarqué pour plus de détails.
Que est la feuille de route ?¶
Le plus simple est de regarder les tags de milestone sur github.
Participer¶
Comment participer¶
Important
We need help to write this section !
Convention de codage¶
Le code source d’atoum respecte certaines conventions. Si vous souhaitez contribuer au projet, votre code devra respecter ces mêmes règles :
- L’indentation est faite avec le caractère de tabulation,
- Les noms des espaces de noms, classes, membres, méthodes et constantes sont en
lowerCamelCase
, - Le code doit être testé.
L’exemple ci-dessous n’a aucun sens, mais il permet de présenter plus en détail la manière dont le code est écrit :
<?php
namespace mageekguy\atoum\coding;
use
mageekguy\atoum,
type\hinting
;
class standards
{
const standardsConst = 'standardsConst';
const secondStandardsConst = 'secondStandardsConst';
public $public;
protected $protected;
private $private = array();
public function publicFunction($parameter, hinting\claass $optional = null)
{
$this->public = trim((string) $parameter);
$this->protected = $optional ?: new hinting\claass();
if (($variable = $this->protectedFunction()) === null)
{
throw new atoum\exception();
}
$flag = 0;
switch ($variable)
{
case self::standardsConst:
$flag = 1;
break;
case self::standardsConst:
$flag = 2;
break;
default:
return null;
}
if ($flag < 2)
{
return false;
}
else
{
return true;
}
}
protected function protectedFunction()
{
try
{
return $this->protected->get();
}
catch (atoum\exception $exception)
{
throw new atoum\exception\runtime();
}
}
private function privateFunction()
{
$array = $this->private;
return function(array $param) use ($array) {
return array_merge($param, $array);
};
}
}
Voici également un exemple de test unitaire :
<?php
namespace tests\units\mageekguy\atoum\coding;
use
mageekguy\atoum,
mageekguy\atoum\coding\standards as testedClass
;
class standards extends atoum\test
{
public function testPublicFunction()
{
$this
->if($object = new testedClass())
->then
->boolean($object->publicFunction(testedClass::standardsConst))->isFalse()
->boolean($object->publicFunction(testedClass::secondStandardsConst))->isTrue()
->if($mock = new \mock\type\hinting\claass())
->and($this->calling($mock)->get = null)
->and($object = new testedClass())
->then
->exception(function() use ($object) {
$object->publicFunction(uniqid());
}
)
->IsInstanceOf('\\mageekguy\\atoum\\exception')
;
}
}
Licences¶
Premièrement, il y a la licence de cette documentation. Celle-ci est CC by-nc-sa 4.0.
Ensuite, vous avez la licence du projet lui-même. Celle-ci est`BSD-3-Clause <https://github.com/atoum/atoum/blob/master/COPYING>`_.