Tester votre code PHP avec EnhancePHP

Tu le sais; Je sais cela. Nous devrions tester notre code plus que nous le faisons. Une des raisons pour lesquelles nous ne le faisons pas, je pense, est que nous ne savons pas exactement comment. Eh bien, je me débarrasse de cette excuse aujourd'hui: je vous apprends à tester votre PHP avec le framework EnhancePHP.


Rencontrez EnhancePHP

Je ne vais pas essayer de vous convaincre de tester votre code; et nous n'allons pas non plus discuter de développement piloté par les tests. Cela a déjà été fait sur Nettuts +. Dans cet article, Nikko Bautista explique exactement pourquoi les tests est une bonne chose et décrit un flux de travail TDD. Lisez-le parfois, si vous n'êtes pas familier avec TDD. Il utilise également la bibliothèque SimpleTest pour ses exemples. Par conséquent, si vous n'aimez pas l'aspect de EnhancePHP, vous pouvez essayer SimpleTest comme alternative..

Comme je l'ai dit, nous utiliserons EnhancePHP. C'est une excellente petite bibliothèque PHP - un seul fichier - qui offre de nombreuses fonctionnalités de test.

Commencez par vous rendre sur leur page de téléchargement et récupérez la dernière version du framework.

Nous allons construire un cours de validation très simple à tester. Il ne fera pas trop: il suffit de revenir vrai si l'article réussit la validation, ou faux si ce n'est pas le cas. Alors, mettez en place un petit projet vraiment simple:

Nous ferons cela est une mode semi-TDD, alors commençons par écrire quelques tests.


Tests d'écriture

Notre petite classe va valider trois choses: adresses e-mail, noms d'utilisateur et numéros de téléphone.

Mais avant d’écrire des tests réels, nous devons configurer notre classe:

  val = nouvelle validation (); 

C'est notre début. remarquez que nous étendons la classe \ Enhance \ TestFixture. Ce faisant, nous faisons savoir à EnhancePHP que toutes les méthodes publiques de cette classe sont des tests, à l'exception des méthodes. installer et abattre. Comme vous pouvez le deviner, ces méthodes s'exécutent avant et après tous vos tests (et non avant et après chacun). Dans ce cas, notre installer méthode va créer un nouveau Validation par exemple et l'assigner à une propriété sur notre instance.

Soit dit en passant, si vous êtes relativement nouveau en PHP, vous n'êtes peut-être pas familier avec ça \ Enhance \ TestFixture syntaxe: à quoi servent les barres obliques? C’est pour cela que vous appelez PHP. consultez la documentation si vous ne le connaissez pas.

Donc, les tests!

Adresses mail

Commençons par valider les adresses email. Comme vous le verrez, faire un test de base est assez simple:

 fonction publique validates_a_good_email_address () $ result = $ this-> val-> validate_email ("[email protected]"); \ Enhance \ Assert :: isTrue ($ result); 

Nous appelons simplement la méthode que nous voulons tester, en lui transmettant une adresse électronique valide et en stockant le $ résultat. Ensuite, nous remettons $ résultat au est vrai méthode. Cette méthode appartient à la \ Améliorer \ Assert classe.

Nous voulons nous assurer que notre classe rejettera les adresses non électroniques. Alors testons cela:

 fonction publique throw_bad_email_addresses () $ val_wrapper = \ Enhance \ Core :: getCodeCoverageWrapper ('Validation'); $ val_email = $ this-> get_scenario ('validate_email'); $ adresses = tableau ("john", "[email protected]", "john @ doe.", "jo*[email protected]"); foreach ($ adresses as $ addr) $ val_email-> avec ($ addr) -> expect (false);  $ val_email-> verifyExpectations (); 

Ceci introduit une fonctionnalité intéressante de EnhancePHP: scénarios. Nous voulons tester plusieurs adresses non-email pour nous assurer que notre méthode sera de retour faux. En créant un scénario, nous encapsulons essentiellement une instance de notre classe dans une qualité EnhancePHP. Nous écrivons beaucoup moins de code pour tester toutes nos adresses non. C'est ce que $ val_wrapper est: une instance modifiée de notre Validation classe. ensuite, $ val_email est l'objet du scénario, un peu comme un raccourci vers le email validé méthode.

Ensuite, nous avons un tableau de chaînes qui ne doivent pas être validées en tant qu’adresses e-mail. Nous allons en boucle sur ce tableau avec un pour chaque boucle. Remarquez comment nous effectuons le test: nous appelons le avec méthode sur notre objet scénario, en lui transmettant les paramètres de la méthode que nous testons. Ensuite, nous appelons le attendre méthode sur cela, et transmettez ce que nous nous attendons à revenir.

Enfin, nous appelons le scénario verifyExpectations méthode.

Ainsi, les premiers tests sont écrits; comment les dirigeons-nous?


Tests en cours

Avant de lancer les tests, nous devons créer notre Validation classe. À l'intérieur lib.validation.php, Commencez par ceci:

  

Maintenant en test.php, nous allons tout tirer ensemble:

  

Premièrement, nous aurons besoin de tous les fichiers nécessaires. Ensuite, nous appelons le runTests méthode, qui trouve nos tests.

Vient ensuite la partie soignée. Lancez un serveur et vous obtiendrez une belle sortie HTML:

Très bien, non? Maintenant, si vous avez PHP dans votre terminal, lancez-le dans le terminal:

EnhancePHP remarque que vous vous trouvez dans un environnement différent et ajuste sa sortie de manière appropriée. Un autre avantage est que si vous utilisez un IDE, comme PhpStorm, capable d'exécuter des tests unitaires, vous pouvez visualiser la sortie de ce terminal directement dans l'EDI..

Vous pouvez également obtenir des sorties XML et TAP. Si c'est ce que vous préférez, passez simplement \ Enhance \ TemplateType :: Xml ou \ Enhance \ TemplateType :: Tap au runTests méthode pour obtenir la sortie appropriée. Notez que son exécution dans le terminal produira également des résultats en ligne de commande, quoi que vous passiez à runTests.

Faire passer les tests

Écrivons la méthode qui fait passer nos tests. Comme vous le savez, c'est le email validé. Au sommet de la Validation classe, définissons une propriété publique:

 public $ email_regex = '/^[\w+-_\.HER++@[\w\.HER++.TOW+$/';

Je mets cela dans une propriété publique afin que l'utilisateur puisse le remplacer par sa propre expression régulière, il pourrait le faire. J'utilise cette version simple d'une regex email, mais vous pouvez la remplacer par votre regex préférée si vous le souhaitez.

Ensuite, il y a la méthode:

 fonction publique validate_email ($ address) return preg_match ($ this-> email_regex, $ address) == 1

Maintenant, nous relançons les tests et:


Écrire plus de tests

Temps pour plus de tests:

Noms d'utilisateur

Créons maintenant des tests pour les noms d'utilisateurs. Notre exigence est simplement qu’il s’agisse d’une chaîne de 4 à 20 caractères composée uniquement de caractères de mots ou de points. Alors:

 fonction publique validates_a_good_username () $ result = $ this-> val-> validate_username ("nom_un_utilisateur_12"); \ Enhance \ Assert :: isTrue ($ result); 

Maintenant, que diriez-vous de quelques noms d’utilisateurs qui ne devraient pas valider:

 fonction publique throws_bad_usernames () $ val_username = $ this-> get_scenario ('validate_username'); $ usernames = array ("nom avec espace", "no! exclaimation! mark", "ts", "thisUsernameIsTooLongItShouldBeBetweenFourAndTwentyCharacters"); foreach ($ usernames as $ name) $ val_username-> avec ($ name) -> expect (false);  $ val_username-> verifyExpectations (); 

Ceci est très similaire à notre refuse_bad_email_addresses une fonction. Notez cependant que nous appelons cela get_scenario méthode: d'où vient-elle? Je résume la fonctionnalité de création de scénario en méthode privée, au bas de notre classe:

 fonction privée get_scenario ($ method) $ val_wrapper = \ Enhance \ Core :: getCodeCoverageWrapper ('Validation'); return \ Enhance \ Core :: getScenario ($ val_wrapper, $ method); 

Nous pouvons utiliser cela dans notre rejeter_noms_de_base et remplacer la création de scénario dans refuse_bad_email_addresses ainsi que. Comme il s’agit d’une méthode privée, EnhancePHP n’essayera pas de l’exécuter comme un test normal, contrairement aux méthodes publiques..

Nous allons faire passer ces tests de la même manière que nous avions fait passer le premier set:

 # Au sommet… public $ username_regex = '/^[\w\.VENench4,20$/'; # et la méthode… public function validate_username ($ username) return preg_match ($ this-> username_regex, $ username) == 1; 

C'est assez fondamental, bien sûr, mais c'est tout ce qui est nécessaire pour atteindre notre objectif. Si nous voulions renvoyer une explication en cas d'échec, vous pourriez faire quelque chose comme ceci:

 fonction publique validate_username ($ username) $ len = strlen ($ username); si ($ len < 4 || $len > 20) return "Le nom d'utilisateur doit comporter entre 4 et 20 caractères";  elseif (preg_match ($ this-> username_regex, $ username) == 1) return true;  else return "Le nom d'utilisateur ne doit contenir que des lettres, des chiffres, des traits de soulignement ou des points."; 

Bien sûr, vous pouvez également vérifier si le nom d'utilisateur existe déjà.

Maintenant, lancez les tests et vous devriez les voir tous passer.

Les numéros de téléphone

Je pense que vous comprenez cela maintenant, finissons donc avec notre exemple de validation en vérifiant les numéros de téléphone:

 fonction publique validates_good_phonenumbers () $ val_phonenumber = $ this-> get_scenario ("validate_phonenumber"); $ numbers = array ("1234567890", "(890) 123-4567", "123-456-7890", "123 456 7890", "(123) 456 7890"); foreach ($ numbers en tant que $ num) $ val_phonenumber-> avec ($ num) -> expect (true);  $ val_phonenumber-> verifyExpectations ();  fonction publique throws_bad_phonenumnbers () $ result = $ this-> val-> validate_phonenumber ("123456789012"); \ Enhance \ Assert :: isFalse ($ result); 

Vous pouvez probablement comprendre le Validation méthode:

 public $ phonenumber_regex = '/ ^ \ d 10 $ | ^ (\ (? \ d 3 \)? [| -] \ d 3 [| -] \ d 4) $ /'; fonction publique validate_phonenumber ($ number) return preg_match ($ this-> phonenumber_regex, $ number) == 1; 

Maintenant, nous pouvons exécuter tous les tests ensemble. Voici à quoi cela ressemble en ligne de commande (mon environnement de test préféré):


Autre fonctionnalité de test

Bien entendu, EnhancePHP peut faire beaucoup plus que ce que nous avons vu dans ce petit exemple. Regardons une partie de cela maintenant.

Nous avons très brièvement rencontré le \ Améliorer \ Assert classe dans notre premier test. Nous ne l'utilisions pas vraiment autrement, car ce n'est pas utile lors de l'utilisation de scénarios. Cependant, c'est là que se trouvent toutes les méthodes d'assertion. Leur beauté réside dans le fait que leurs noms rendent leur fonctionnalité incroyablement évidente. Les exemples de test suivants passeraient:

  • \ Enhance \ Assert :: areIdentical ("Nettuts +", "Nettuts +")
  • \ Enhance \ Assert :: areNotIdentical ("Nettuts +", "Psdtuts +")
  • \ Enhance \ Assert :: isTrue (true)
  • \ Enhance \ Assert :: isFalse (false)
  • \ Enhance \ Assert :: contient ("Net", "Nettuts +")
  • \ Enhance \ Assert :: isNull (null)
  • \ Enhance \ Assert :: isNotNull ('Nettust +')
  • \ Enhance \ Assert :: isInstanceOfType ('Exception', nouvelle exception (""))
  • \ Enhance \ Assert :: isNotInstanceOfType ('String', nouvelle exception (""))

Il existe également quelques autres méthodes d'assertion. vous pouvez consulter la documentation pour une liste complète et des exemples.

Se moque

EnhancePHP peut également faire des simulacres et des moignons. Vous n'avez pas entendu parler de moqueries et de moqueries? Eh bien, ils ne sont pas trop compliqués. Un mock est un wrapper pour objet, qui peut garder une trace de quelles méthodes sont appelées, avec quelles propriétés elles sont appelées et quelles valeurs sont retournées. Une maquette aura un test à vérifier, comme nous le verrons.

Voici un petit exemple de maquette. Commençons par une classe très simple qui compte:

 num = $ this-> num + $ num; retourne $ this-> num; 

Nous avons une fonction: incrément, qui accepte un paramètre (mais vaut par défaut 1) et incrémente le $ num propriété par ce nombre.

Nous pourrions utiliser cette classe si nous construisions un tableau de bord:

 class Tableau de bord public $ home = 0; public $ away = 0; fonction publique __construct ($ home, $ absent) $ this-> home_counter = $ home; $ this-> away_counter = $ away;  fonction publique score_home () $ this-> home = $ this-> home_counter-> increment (); retourne $ this-> home;  public function score_away () $ this-> away = $ this-> away_counter-> increment (); retourne $ this-> home; 

Maintenant, nous voulons tester pour nous assurer que le Compteur méthode d'instance incrément fonctionne correctement lorsque le Tableau de bord les méthodes d'instance l'appellent. Nous créons donc ce test:

 class ScoreboardTest étend \ Enhance \ TestFixture fonction publique score_home_calls_increment () $ home_counter_mock = \ Enhance \ MockFactory :: createMock ("Counter"); $ away_counter = new Counter (); $ home_counter_mock-> addExpectation (\ Enhance \ Expect :: method ('increment')); $ scoreboard = nouveau tableau de bord ($ home_counter_mock, $ away_counter); $ scoreboard-> score_home (); $ home_counter_mock-> verifyExpectations ();  \ Enhance \ Core :: runTests ();

Notez que nous commençons par créer $ home_counter_mock: nous utilisons l’usine fictive EnhancePHP, en lui donnant le nom de la classe à laquelle nous nous moquons. Ceci retourne une instance "wrapped" de Compteur. Ensuite, nous ajoutons une attente, avec cette ligne

 $ home_counter_mock-> addExpectation (\ Enhance \ Expect :: method ('increment'));

Notre attente dit simplement que nous attendons la incrément méthode à appeler.

Après cela, nous continuons à créer le Tableau de bord exemple, et appelez score_home. Ensuite nous verifyExpectations. Si vous exécutez ceci, vous verrez que notre test réussit.

Nous pourrions également indiquer quels paramètres nous souhaitons qu'une méthode sur l'objet fictif soit appelée, avec quelle valeur est renvoyée ou combien de fois la méthode doit être appelée, avec quelque chose comme ceci:

 $ home_counter_mock-> addExpectation (\ Enhance \ Expect :: method ('increment') -> avec (10)); $ home_counter_mock-> addExpectation (\ Enhance \ Expect :: method ('increment') -> times (2)); $ home_counter_mock-> addExpectation (\ Enhance \ Expect :: method ('increment') -> return (1)); $ home_counter_mock-> addExpectation (\ Enhance \ Expect :: method ('increment') -> avec (3) -> times (1)); $ home_counter_mock-> addExpectation (\ Enhance \ Expect :: method ('increment') -> avec (2) -> return (2));

Je devrais mentionner que, avec et fois montrera des tests ratés si les attentes ne sont pas signifiées, résultats ne le fait pas Vous devrez stocker la valeur de retour et utiliser une affirmation très précise. Je ne sais pas pourquoi c'est le cas, mais chaque bibliothèque a ses bizarreries :). (Vous pouvez en voir un exemple dans les exemples de bibliothèques dans Github.)

Stubs

Ensuite, il y a des talons. Un talon remplit un objet et une méthode réels, renvoyant exactement ce que vous lui dites. Alors, disons que nous voulons nous assurer que notre Tableau de bord instance utilise correctement la valeur qu'il reçoit de incrément, nous pouvons stub un Compteur par exemple, nous pouvons contrôler ce que incrément retournera:

 class ScoreboardTest étend \ Enhance \ TestFixture fonction publique score_home_calls_increment () $ home_counter_stub = \ Enhance \ StubFactory :: createStub ("Counter"); $ away_counter = new Counter (); $ home_counter_stub-> addExpectation (\ Enhance \ Expect :: method ('increment') -> return (10)); $ scoreboard = nouveau tableau de bord ($ home_counter_stub, $ away_counter); $ resultat = $ scoreboard-> score_home (); \ Enhance \ Assert :: areIdentical ($ result, 10);  \ Enhance \ Core :: runTests ();

Ici, nous utilisons \ Enhance \ StubFactory :: createStub pour créer notre compteur de bouts. Ensuite, nous ajoutons une attente que la méthode incrément retournera 10. Nous pouvons voir que le résultat correspond à ce que nous attendions, étant donné notre code.

Pour plus d’exemples de simulacres et de moignons avec la bibliothèque EnhancePHP, consultez le rapport Github..


Conclusion

Eh bien, voici un aperçu des tests en PHP, en utilisant le framework EnhancePHP. C'est un framework incroyablement simple, mais il fournit tout ce dont vous avez besoin pour faire de simples tests unitaires sur votre code PHP. Même si vous choisissez une méthode / un cadre différent pour tester votre PHP (ou peut-être rouler le vôtre!), J'espère que ce tutoriel a suscité un intérêt pour tester votre code, et comme il peut être simple.

Mais vous avez peut-être déjà testé votre PHP. Dites-nous tous ce que vous utilisez dans les commentaires; Après tout, nous sommes tous ici pour apprendre les uns des autres! Merci beaucoup de votre visite!