Démarrez vos tests PHP avec Codeception
Publié: 2022-03-11Avant de passer à Codeception et PHP, nous devrions couvrir les bases et commencer par expliquer pourquoi nous avons besoin de tests dans les applications en premier lieu. Peut-être pourrions-nous terminer un projet sans perdre de temps en tests, du moins cette fois ?
Bien sûr, vous n'avez pas besoin de tests pour tout; par exemple, lorsque vous souhaitez créer une autre page d'accueil. Vous n'avez probablement pas besoin de tests lorsque votre projet contient des pages statiques liées par un routeur.
Cependant, vous avez certainement besoin de tests lorsque :
- Votre équipe utilise BDD/TDD.
- Votre dépôt Git contient plus de quelques commits.
- Vous êtes un vrai professionnel, travaillant sur un projet sérieux.
Vous pouvez vous excuser en disant que vous avez déjà un service de test dédié, un groupe de personnes qui effectuent des tests et en écrivent de nouveaux en cas de besoin. Mais pouvez-vous imaginer combien de temps prendra la correction des bogues après avoir ajouté de nouvelles fonctionnalités à votre projet ?
Que résout le test ?
Tout d'abord, décidons quel type de problèmes peuvent être résolus grâce aux tests. Vous ne pouvez pas vous débarrasser de toutes vos erreurs avec les tests, mais vous pouvez décrire le comportement attendu dans les cas de test. Les erreurs peuvent se trouver dans vos cas de test. Le code spaghetti reste du code spaghetti même lorsque vous utilisez des cas de test.
Cependant, vous pouvez être sûr que votre code sera modifié par la suite (en corrigeant des erreurs ou en ajoutant de nouvelles fonctionnalités), de sorte que votre code sera toujours exempt d'erreurs décrites dans le test. En outre, même des tests bien écrits peuvent parfois être utilisés dans la documentation, car vous pouvez y voir comment se déroulent des scénarios typiques et vérifier le comportement attendu. Nous pouvons dire que les tests sont un investissement modeste mais crucial pour l'avenir.
Alors, quel genre de tests pouvons-nous utiliser?
- Tests unitaires : tests de bas niveau qui vérifient de petits morceaux de votre code - les méthodes de votre classe isolées des autres codes.
- Tests d'intégration : Les tests d'intégration vérifient une partie de votre application, ils peuvent contenir plusieurs classes ou méthodes, mais doivent être limités à une fonctionnalité. Ce test devrait également vérifier comment les différentes classes interagissent.
- Tests fonctionnels : teste des requêtes spécifiques à votre application : réponse du navigateur, modifications de la base de données, etc.
- Tests d'acceptation : dans la plupart des cas, les tests d'acceptation consistent à vérifier si l'application répond à toutes les exigences du client.
Pour clarifier, disons que nous illustrons le processus avec quelque chose de tangible, comme un bâtiment. Un bâtiment est composé de petits blocs qui forment des murs. Chaque brique doit répondre à des exigences spécifiées ; il doit supporter la charge requise, avoir un volume et une forme spécifiques, etc. Ce sont des tests unitaires. L'idée des tests d'intégration est de vérifier à quel point les briques adhèrent étroitement et précisément les unes aux autres, comment elles sont intégrées dans un certain élément du bâtiment. Les tests fonctionnels peuvent être assimilés à des tests sur un seul mur du bâtiment, pour vérifier si l'intérieur est protégé ou non des intempéries, et s'il est possible ou non de voir le soleil à travers la fenêtre. Les tests d'acceptation consistent à tester l'ensemble du bâtiment en tant que produit complet : ouvrez la porte, entrez, fermez la porte, allumez la lumière, montez au deuxième étage et jetez un coup d'œil au jardin à l'extérieur du bâtiment.
Rencontrez Codeception
Cependant, cette division est conditionnelle et il est parfois difficile de résister à la tentation de mélanger différents types de tests.
De nombreux développeurs utilisent des tests unitaires et prétendent que cela suffit. J'étais l'un de ces développeurs; J'ai trouvé l'utilisation de différents systèmes pour différents types de tests trop difficile et chronophage. Il y a quelque temps, j'ai décidé de trouver quelque chose de plus utile que PHPUnit ; Je voulais être meilleur pour tester mon code, mais je ne voulais pas lire et apprendre des tonnes de documentation et rechercher les pièges. C'est ainsi que j'ai découvert Codeception. Au début, j'étais sceptique, comme nous le sommes souvent quand il s'agit de quelque chose de nouveau (ce projet a cinq ans, donc techniquement, il ne peut pas être considéré comme "nouveau"), mais après avoir joué avec pendant quelques jours , j'ai conclu que Codeception est un système très utile et puissant.
Alors, comment installer Codeception ? C'est aussi simple que possible :
$ composer require "codeception/codeception" $ php vendor/bin/codecept bootstrap
Après l'installation, vous trouverez un nouveau dossier nommé tests dans votre projet, et il y aura des sous-dossiers nommés acceptation, fonctionnel et unité . Il semble que nous pouvons commencer à écrire nos tests. Cool, mais quelle est la prochaine?
Maintenant, essayez d'ajouter un test d' acceptation standard Hello World.
$ php vendor/bin/codecept generate:cept acceptance HelloWorld
Maintenant, nous obtenons un fichier de test d'acceptation tests/acceptance/HelloWorldCept.php, avec le contenu suivant :
<?php $I = new AcceptanceTester($scenario); $I->wantTo('perform actions and see result');
La variable par défaut, nommée $I
, n'est pas simplement une lettre ; c'est un personnage. Qu'est-ce qui conduit les tests ? Le testeur, évidemment. Ce testeur ouvre la page ou la classe de votre site Web, en fait quelque chose et vous montre le résultat final de ses actions. Vous verrez ce qui a fonctionné et ce qui n'a pas fonctionné. C'est pourquoi cet objet est nommé $I
et qu'il contient des méthodes appelées wantTo()
, see()
ou amOnPage()
.
Alors, réfléchissons comme le ferait un testeur aux moyens de vérifier l'opérabilité d'une page. La première approche consiste à ouvrir la page et à rechercher une phrase. Cela prouve que la page est disponible pour les visiteurs.
Cela devrait être facile :
<?php $I->amOnPage('/'); $I->see('Welcome');
Nous pouvons utiliser cette commande pour exécuter les tests de Codeception :
$ php vendor/bin/codecept run
On voit tout de suite que quelque chose ne va pas. À première vue, il semble que le message soit trop long et peu clair, mais quand on y regarde de plus près, tout devient évident.
Nous avons eu un test, Acceptance , et il a détecté une erreur :
Acceptance Tests (1) Perform actions and see result (HelloWorldCept) Error ---------- 1) Failed to perform actions and see result in HelloWorldCept (tests/acceptance/HelloWorldCept .php) [GuzzleHttp\Exception\ConnectException] cURL error 6: Could not resolve host: localhost (see http://curl.haxx.se/libcurl/c/libcurl-errors.html)
C'est le coupable : localhost n'est pas disponible.
Et voici les étapes du scénario de notre test :
1. $I->amOnPage("/")
Ok, ouvrons tests/acceptance.suite.yml et changeons l' url: http://localhost/
en quelque chose qui est réellement disponible. Dans mon cas, il s'agit de mon hébergeur de test local, url: https://local.codeception-article.com/
Relancez le test et voici ce que vous devriez obtenir :
Acceptance Tests (1) --------------------------------------------------------------------------------------- Perform actions and result (HelloWorldCept) Ok
Hourra ! Notre premier test réussi !
Bien sûr, amOnPage()
n'est pas la seule méthode de test disponible, nous l'avons simplement choisie pour notre exemple. Toutes les méthodes de test Codeception peuvent être réparties dans les groupes suivants :
- Interaction avec la page :
fillField()
,selectOption()
,submitForm()
,click()
- Assertions.
see()
,dontSee()
,seeElement()
,seeInCurrentUrl()
,seeCheckboxIsChecked()
,seeInField()
,seeLink()
. À toutes ces méthodes, vous pouvez ajouter un suffixe et l'utiliser lorsque vous avez besoin d'une méthode qui n'interrompra pas le scénario de test lorsque quelque chose est introuvable. - Méthodes de cookies :
setCookie()
,grabCookie()
,seeCookie()
- Commentaire et description des scénarios de test :
amGoingTo()
,wantTo()
,expect()
. Utilisez ces méthodes pour obtenir des tests bien commentés et décrits, ce qui vous aidera à vous souvenir des objectifs du test.
Donc, si nous devions tester la page de messagerie de réinitialisation du mot de passe, nous pourrions le faire de cette façon :
<?php $I = new AcceptanceTester($scenario); $I->wantTo('Test forgotten password functionality'); $I->amOnPage('/forgotten') $I->see('Enter email'); $I->fillField('email', '[email protected]'); $I->click('Continue'); $I->expect('Reset password link not sent for incorrect email'); $I->see('Email is incorrect, try again'); $I->amGoingTo('Fill correct email and get link'); $I->see('Enter email'); $I->fillField('email', '[email protected]'); $I->click('Continue'); $I->expect('Reset password link sent for correct email'); $I->see('Please check your email for next instructions');
Il semble que cela devrait le faire, mais que se passe-t-il s'il y a des parties chargées en Ajax sur la page ? Peut-on tester une page comme ça ? La réponse est que Codeception utilise PhpBrowser, basé sur Symfony BrowserKit et Guzzle, par défaut. C'est simple, rapide et vous n'avez besoin que de curl pour l'utiliser.

Vous pouvez également utiliser Selenium et tester des pages avec de vrais navigateurs. Oui, ce sera plus lent, mais vous pourrez également tester JavaScript.
Tout d'abord, vous devez installer le pilote Selenium, modifier l'acceptation.suite.yml et reconstruire la classe AcceptanceTester. Après cela, vous pouvez utiliser les méthodes wait()
et waitForElement()
. Et, plus intéressant, vous pourrez économiser votre temps et vos ressources en utilisant les méthodes saveSessionSnapshot()
et loadSessionSnapshot()
. Cette méthode vous permet de stocker l'état de la session et de démarrer de nouveaux tests dans des sessions antérieures. Ceci est utile dans certaines situations, par exemple, dans le processus d'autorisation de test.
Ainsi, nous nous retrouvons avec une capacité simple, mais puissante, de tester de nombreuses fonctions.
Test fonctionel
OK, il est temps de passer aux tests fonctionnels.
$ php vendor/bin/codecept generate:cept functional HelloWorld
Et voici ce que nous obtenons :
<?php $I = new FunctionalTester($scenario); $I->amOnPage('/'); $I->see('Welcome');
Attends quoi?
Non, ce n'est pas une erreur. Les tests fonctionnels doivent être écrits de la même manière que les tests d'intégration. La différence est que les tests fonctionnels interagissent directement avec votre application. Cela signifie que vous n'avez pas besoin d'un serveur Web pour exécuter des tests fonctionnels et que vous avez plus de capacité pour tester différentes parties de votre application.
Cela signifie que la prise en charge de tous les frameworks fait défaut, mais la liste des frameworks pris en charge est longue : Symfony, Silex, Phalcon, Yii, Zend Framework, Lumen, Laravel. Cela devrait être suffisant pour la plupart des cas et la plupart des développeurs. Veuillez consulter la documentation du module de Codeception pour obtenir une liste des fonctions disponibles, puis activez-la simplement functional.suite.yml
.
Avant de passer aux tests unitaires, permettez-moi de faire une petite digression. Comme vous l'avez peut-être remarqué, nous avons créé nos tests avec la clé cept :
$ php vendor/bin/codecept generate: cept acceptance HelloWorld
Ce n'est pas la seule façon de créer des tests. Il existe aussi ces tests . La différence est que vous pouvez structurer plusieurs scénarios associés dans une classe :
$ php vendor/bin/codecept generate:cest acceptance HelloWorld <?php class HelloWorldCest { public function _before(AcceptanceTester $I) { $I->amOnPage('/forgotten') } public function _after(AcceptanceTester $I) { } // tests public function testEmailField(AcceptanceTester $I) { $I->see('Enter email'); } public function testIncorrectEmail(AcceptanceTester $I) { $I->fillField('email', '[email protected]'); $I->click('Continue'); $I->see('Email is incorrect, try again'); } public function testCorrectEmail(AcceptanceTester $I) { $I->fillField('email', '[email protected]'); $I->click('Continue'); $I->see('Please check your email for next instructions'); } }
Dans cet exemple, les méthodes _before()
et _after()
sont exécutées avant et après chaque test. Une instance de la classe AcceptanceTester
est transmise à chaque test, vous pouvez donc l'utiliser de la même manière que dans les tests cest. Ce style de tests peut être utile dans certaines situations, il convient donc de le garder à l'esprit.
Tests unitaires
Il est temps de faire des tests unitaires.
Codeception est basé sur PHPUnit, vous pouvez donc utiliser des tests écrits pour PHPUnit. Pour ajouter de nouveaux tests PHPUnit, utilisez l'approche suivante :
$ php vendor/bin/codecept generate:phpunit unit HelloWorld
Ou héritez simplement de vos tests sur \PHPUnit_Framework_TestCase
.
Mais si vous voulez quelque chose de plus, vous devriez essayer les tests unitaires de Codeception :
$ php vendor/bin/codecept generate:test unit HelloWorld <?php class HelloWorldTest extends \Codeception\TestCase\Test { /** * @var \UnitTester */ protected $tester; protected function _before() { } protected function _after() { } // tests public function testUserSave() { $user = User::find(1); $user->setEmail('[email protected]'); $user->save(); $user = User::find(1); $this->assertEquals('[email protected]', $user->getEmail()); } }
Rien d'anormal pour l'instant. Les méthodes _before()
et _after()
sont setUp()
et tearDown()
et s'exécuteront avant et après chaque test.
Le principal avantage de ce test réside dans sa capacité à étendre votre processus de test en incluant des modules qui peuvent être activés dans unit.suite.yml
:
- Accès au cache mémoire et aux bases de données pour suivre les modifications (MySQL, SQLite, PostgreSQL, MongoDB sont pris en charge)
- Test des applications REST/SOAP
- Files d'attente
Chaque module a ses propres fonctionnalités, il est donc préférable de vérifier la documentation et de collecter les informations nécessaires pour chaque module avant de procéder à des tests réels.
De plus, vous pouvez utiliser le package Codeception/Specify (qui doit être ajouté à composer.json
) et écrire une description comme celle-ci :
<?php class HelloWorldTest extends \Codeception\TestCase\Test { use \Codeception\Specify; private $user; protected function _before() { $this->user = User::find(1); } public function testUserEmailSave() { $this->specify("email can be stored", function() { $this->user->setEmail('[email protected]'); $this->user->save(); $user = User::find(1); $this->assertEquals('[email protected]', $user->getEmail()); }); } }
Le code PHP à l'intérieur de ces fonctions de fermeture est isolé, donc les modifications à l'intérieur n'affecteront pas le reste de votre code. Les descriptions vous aideront à rendre le test plus lisible et à identifier plus facilement les tests ayant échoué.
En option, vous pouvez utiliser le package Codeception\Verify
pour une syntaxe de type BDD :
<?php public function testUserEmailSave() { verify($map->getEmail())->equals('[email protected]'); }
Et bien sûr, vous pouvez utiliser des stubs :
<?php public function testUserEmailSave() { $user = Stub::make('User', ['getEmail' => '[email protected]']); $this->assertEquals('[email protected]', $user->getEmail()); }
Verdict : la détection de code permet d'économiser du temps et des efforts
Alors, que devez-vous attendre de Codeception ? C'est pour qui ? Y a-t-il des mises en garde ?
À mon avis, ce framework de test convient à toutes sortes d'équipes différentes : grandes et petites, débutants et professionnels de PHP aguerris, ceux qui utilisent un framework populaire et ceux qui n'utilisent aucun framework.
En tout cas, tout se résume à ceci : Codeception est prêt pour le prime time.
C'est un cadre mature et bien documenté qui peut facilement être étendu par de nombreux modules. Codeception est moderne, mais basé sur le PHPUnit qui a fait ses preuves, ce qui devrait rassurer les développeurs qui ne veulent pas trop expérimenter.
Il fonctionne bien, ce qui signifie qu'il est rapide et ne nécessite pas trop de temps et d'efforts. Mieux encore, il est relativement facile à maîtriser et une documentation abondante devrait faciliter un processus d'apprentissage sans tracas.
Codeception est également facile à installer et à configurer, mais il propose de nombreuses options avancées. Bien que la plupart des utilisateurs n'en aient pas besoin (ou même la plupart), tout dépend de ce que vous avez l'intention d'en faire. Vous pouvez commencer par les bases, et les fonctionnalités supplémentaires vous seront utiles tôt ou tard.