Documentation officielle de l'outil de génération PHPUnitGen

PHPUnitGen, un puissant outil d'analyse de code PHP et de génération de tests unitaires

Paul Thébaud

Si vous voulez réagir à cette documentation de PHPUnitGen, ou encore, si vous souhaitez partager votre expérience avec cet outil d’analyse de code, un espace de discussion vous est proposé sur le forum. N’hésitez pas à partager votre avis. Commentez

- Titre : Documentation officielle de l'outil de génération PHPUnitGen

- Auteur : Paul Thébaud

- Parution : 25 juin 2018

- Public visé :

- Licence : Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright ® 2018 Paul Thebaud. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Sommaire

- I. Présentation générale de l'application

- II. Installation

- III. Exemple d'utilisation avec un code PHP

- IV. Utilisation en ligne de commande

- IV-A. Paramètres du fichier de Configuration

- V. Annotations

- V-A. Génération automatique

- V-B. Arguments des annotations

- V-C. Instanciation de classes

- V-D. Getter et setter

- V-E. Assertions sur les résultats d'une méthode

- V-F. Paramètres de méthode

- V-G. Création de Mock

- VI. Remerciements

I - Présentation générale de l'application

PhpUnitGen est un outil d'analyse de code PHP et de génération de tests unitaires.

Il a été développé par Paul Thébaud.

PhpUnitGen est utilisable en ligne, car il analyse le code PHP plutôt que d'utiliser les Reflections PHP.

Toutefois, il existe une version installable avec Composer.

Comme de nombreux outils, il est configurable dans son fonctionnement ou son design.
Grâce au bouton de configuration — en haut à droite lorsque vous êtes sur l'application —, vous pouvez modifier ces paramètres :

- Taille de l'éditeur : permet de régler la hauteur de l'éditeur de code PHP.

- Thème : permet de changer les couleurs de l'application (en plus il y a des surprises quand vous utilisez l'application).

- Génération automatique : permet de générer automatiquement les tests unitaires des méthodes getters/setters, ou l'instanciation des classes ou traits.

- Analyse des méthodes privées/protégées : permet d'activer ou de désactiver la génération de squelettes pour les méthodes privées ou protégées.

- Analyse des interfaces : permet d'activer ou de désactiver la génération de squelettes pour les interfaces PHP.

- PHPDoc des tests générés : permet de gérer une liste des annotations PHPDoc (@author par exemple) qui se trouveront dans l'entête de la classe de test.

Note

Cette configuration sera automatiquement sauvegardée à chaque modification, directement dans le stockage de votre navigateur. Il est possible de la réinitialiser avec le bouton « reset », en bas à gauche de la page de configuration.

L'application web peut ensuite être utilisée de deux manières différentes :

- soit vous importez un fichier PHP ;

- soit vous utilisez l'éditeur de code PHP à votre disposition (n'oubliez pas que vous pouvez fournir le nom qu'aura la classe générée, dans le champ au-dessus de l'éditeur).
Enfin, lorsque vous êtes sur cette documentation, vous pouvez juste cliquer sur le bouton en bas à droite pour aller sur l'application PhpUnitGen.

II - Installation

La meilleure façon d'installer PhpUnitGen est via Composer. Cela permettra d'effectuer facilement les mises à jour.
Composer est le gestionnaire de package pour les projets PHP.

1. $ composer require --dev paulthebaud/phpunit-generator ^2.0

L'option --dev est utilisée pour installer le package uniquement dans un environnement de développement.
PhpUnitGen utilise PHP 7.1, mais est aussi compatible (et testé avec Travis) avec PHP 7.2.

III - Exemple d'utilisation avec un code PHP

Voici un exemple d'utilisation de PhpUnitGen dans un script PHP.

1. <?php

3. use PhpUnitGen\Configuration\BaseConfig;

4. use PhpUnitGen\Container\ContainerFactory;

5. use PhpUnitGen\Executor\ExecutorInterface\ExecutorInterface;

7. // Importer l'autoload Composer

8. require 'vendor/autoload.php';

10. // Créer la configuration

11. $config = new BaseConfig([ /* ... des options ... */ ]);

13. // Créer le conteneur de dépendances

14. $container = (new ContainerFactory())->invoke($config);

16. $myTestClass = 'MyClassTest';

17. $myCode = "<?php class MyClass { /* ... du code PHP ... */ }";

19. // Exécuter PhpUnitGen sur le code et enregistrer les résultats

20. $myUnitTestsSkeleton = $container->get(ExecutorInterface::class)->invoke($myCode, $myTestClass);

22. // Afficher les résultats

23. echo $myUnitTestsSkeleton;

Note

new BaseConfig() ou $container->get(ExecutorInterface::class)->invoke($myCode, $myTestClass) sont susceptibles de lever des exceptions PHP, si la configuration fournie est invalide par exemple.

IV - Utilisation en ligne de commande

Quand vous installez le package Composer, vous pouvez utiliser PhpUnitGen en ligne de commande. Il faut vous placer à la racine de votre projet Composer.

1. $ php ./vendor/bin/phpunitgen

Pour cette commande, vous aurez besoin d'un fichier de configuration écrit en YAML, JSON ou PHP.

- L'exemple YAML se trouve ici here.

- L'exemple JSON se trouve ici here.

- L'exemple PHP se trouve ici here.
Par défaut (sans option), PhpUnitGen cherchera un fichier de configuration nommé phpunitgen.yml à la racine du projet.
Mais si vous souhaitez utiliser une configuration personnalisée, vous pouvez utiliser une option :

1. $ php ./vendor/bin/phpunitgen --config=my/custom/config.yml

3. $ php ./vendor/bin/phpunitgen -c=my/custom/config.yml

Pour utiliser PhpUnitGen sur un seul fichier (l'utilisation de l'option file aura besoin d'une source et d'une cible étant des fichiers) :

1. $ php ./vendor/bin/phpunitgen --file source/file.php target/file.php

3. $ php ./vendor/bin/phpunitgen -f source/file.php target/file.php

Pour utiliser PhpUnitGen sur un seul dossier (l'utilisation de l'option dir aura besoin d'une source et d'une cible étant des dossiers) :

1. $ php ./vendor/bin/phpunitgen --dir source/dir target/dir

3. $ php ./vendor/bin/phpunitgen -d source/dir target/dir

Pour utiliser PhpUnitGen avec la configuration par défaut (l'utilisation de l'option default aura besoin d'une source et d'une cible) :

1. $ php ./vendor/bin/phpunitgen --default --file source/file.php target/file.php

2. $ php ./vendor/bin/phpunitgen --default --dir source/dir target/dir

4. $ php ./vendor/bin/phpunitgen -D -f source/file.php target/file.php

5. $ php ./vendor/bin/phpunitgen -D -d source/dir target/dir

Note

- Si vous utilisez l'option default avec l'option config, la configuration sera ignorée et PhpUnitGen utilisera la configuration par défaut.

- Si vous utilisez l'option default, et que vous ne fournissez pas d'option dir ou file, PhpUnitGen considèrera que les source et cible sont des dossiers.

- Étant donné que PhpUnitGen utilise le package de la Console Symfony, vous pouvez combiner plusieurs raccourcis d'options ensemble : $ php ./vendor/bin/phpunitgen -fc my/custom/config.yml source/file.php target/file.php analysera un seul fichier avec la configuration personnalisée fournie.

IV-A - Paramètres du fichier de Configuration

Un fichier de configuration aura besoin de tous les paramètres suivants :

- overwrite [boolean] : utilisez la valeur true si vous voulez que les fichiers qui existent déjà soient supprimés.

- backup [boolean] : utilisez la valeur true si vous voulez qu'un backup soit créé avant de supprimer les fichiers quand l'option overwrite est égale à true. Les fichiers de backup auront le nom suivant : your_file.php.bak

- interface [boolean] : utilisez la valeur true si vous voulez générer des squelettes de tests pour les interfaces PHP.

- private [boolean] : utilisez la valeur true si vous voulez générer des squelettes de tests pour les méthodes privées ou protégées.

- auto [boolean] : utilisez la valeur true si vous voulez générer automatiquement les tests unitaires des méthodes getter / setter, ou les instanciations des classes et des traits.

- ignore [boolean] : utilisez la valeur true si vous voulez utiliser les erreurs peu importantes (fichier impossible à analyser dans un dossier…).

- exclude [string ou null] : une expression régulière PHP pour les fichiers qui ne devraient pas être analysés. Utilisez null en valeur si vous ne souhaitez pas filtrer les fichiers avec ce mode.
C'est une condition que les fichiers ne doivent pas remplir pour être analysés.

- include [string ou null] : une expression régulière PHP pour les fichiers qui doivent être analysés. Utilisez null en valeur si vous ne souhaitez pas filtrer les fichiers avec ce mode.
C'est une condition que les fichiers doivent remplir pour être analysés.

- dirs [array] : un tableau de dossiers source: cible. PhpUnitGen analysera chaque fichier du dossier source (et les sous-dossiers), puis générera les fichiers de tests dans le dossier cible. La valeur null permet de ne pas analyser de dossier.

- files [array] : un tableau de fichiers source: cible. PhpUnitGen analysera chaque fichier source, puis générera les fichiers de tests cibles. La valeur null permet de ne pas analyser de fichier.

V - Annotations

Au-delà de fournir une configuration de la génération des squelettes de tests, PhpUnitGen apporte aussi des annotations PHPDoc que vous pouvez utiliser dans vos fichiers à tester :

- instanciation de classe : @PhpUnitGen\construct ;

- génération de tests unitaires pour les méthodes getters et setters : @PhpUnitGen\get et @PhpUnitGen\set ;

- paramètres des méthodes : @PhpUnitGen\params ;

- méthodes d'assertion de PHPUnit : @PhpUnitGen\... avec une assertion PHPUnit (@PhpUnitGen\assertTrue par exemple) ;

- création de mock : @PhpUnitGen\mock.
Ces annotations DOIVENT être écrites dans le bloc PHPDoc. Elles commencent toujours par @PhpUnitGen ou @Pug (qui n'est pas sensible à la casse, donc vous pouvez écrire @phpunitgen).

1. <?php

2. /**

3. * Les suivantes marchent !

4. * @PhpUnitGen\assertTrue()

5. * @Pug\assertTrue()

6. * @pug\assertTrue()

7. * @phpUnitGen\assertTrue()

8. *

9. * Celle-ci ne marche pas :

10. * @PhpUnitGenerator\assertTrue()

11. */

12. function validateSomething(): bool { /* du code PHP */ }

Vous pouvez trouver quelques exemples basiques d'utilisation des annotations ici avec des fichiers d'entrée et leurs résultats avec PhpUnitGen.

Note

Les annotations PhpUnitGen sont créées pour générer des tests simples. Si vous voulez tester des méthodes complexes, vous devriez écrire vos tests unitaires vous-même.

V-A - Génération automatique

Quand vous utilisez le paramètre auto de la configuration, PhpUnitGen détectera les méthodes getter/setter et générera les tests unitaires pour ces méthodes.

Dans PhpUnitGen, pour une propriété $name, un getter est une méthode getName, un setter est une méthode setName, et la classe ou le trait doit avoir une propriété $name.

PhpUnitGen va tester ces méthodes avec un paramètre généré automatiquement, qui aura le type de retour de la méthode pour un getter, ou le type d'argument de la méthode pour un setter.

PhpUnitGen va aussi générer les instanciations des classes ou des traits s’ils ont une méthode __construct. Il utilisera ici aussi des paramètres générés automatiquement, alors soyez prudent avec ces instanciations automatiques.

V-B - Arguments des annotations

Certaines annotations auront besoin de paramètres. Quand il génère les squelettes, PhpUnitGen analyse ces paramètres comme du contenu JSON, alors tous les paramètres doivent être indiqués par des " lorsque ce ne sont pas des tableaux ou des objets. Dans ces paramètres, vous pouvez écrire du code PHP, comme une création de Mock : "$this->createMock('MaClasse')".

N'oubliez pas d'échapper l'antislash \ ou le guillemet " avec un antislash \.

V-C - Instanciation de classes

Quand PhpUnitGen génère un squelette de tests, il ne pourra pas toujours détecter le constructeur, car il n'analyse qu'un seul fichier. Si vous fournissez cette annotation dans la documentation de la classe, il créera l'instanciation pour les tests avec vos paramètres.

1. <?php

2. namespace Company;

3. /**

4. * Construit l'instance de tests avec 'new Employee("John", "0123456789")'

5. * @PhpUnitGen\construct(["'John'", "'012-345-6789'"])

6. */

7. class Employee extends AbstractPerson

8. {

9. public function __construct(string $name, string $cellphone) { /* du code PHP */ }

10. }

Si vous voulez instancier une autre classe que celle d'origine (quand vous écrivez les tests d'une classe abstraite par exemple), vous pouvez fournir un argument indiquant la classe à instancier :

1. <?php

2. namespace Company;

3. /**

4. * Construit l'instance de tests avec 'new \Company\Employee("John", "0123456789")'

5. * @PhpUnitGen\construct("\Company\Employee", ["'John'", "'0123456789'"])

6. */

7. abstract class AbstractPerson { /* du code PHP */ }

V-D - Getter et setter

Pour générer les tests pour un getter ou un setter, PhpUnitGen propose deux annotations.

1. <?php

2. class Employee {

3. private $name;

4. /**

5. * Vérifie que quand la méthode est appelée, la valeur de la propriété $name est retournée.

6. * @PhpUnitGen\get

7. */

8. public function getName(): string

9. {

10. return $this->name;

11. }

12. /**

13. * Vérifie que quand la méthode est appelée, la valeur de la propriété $name est changée.

14. * @PhpUnitGen\set

15. */

16. public function setName(string $name): void

17. {

18. $this->name = $name;

19. }

20. }

Si vous voulez indiquer à PhpUnitGen que la méthode n'est pas nommée à partir de la propriété, ajoutez juste le nom de la propriété dans l'annotation.

1. <?php

2. class Employee {

3. private $phone;

4. /**

5. * Vérifie que quand la méthode est appelée, la valeur de la propriété $phone est retournée.

6. * @PhpUnitGen\get("phone")

7. */

8. public function getCellphone(): string

9. {

10. return $this->phone;

11. }

12. /**

13. * Vérifie que quand la méthode est appelée, la valeur de la propriété $phone est changée.

14. * @PhpUnitGen\set("phone")

15. */

16. public function setCellphone(string $phone): void

17. {

18. $this->phone = $phone;

19. }

20. }

Note

Les annotations get et set supportent les méthodes statiques ou d'instance pour les classes, les traits et les interfaces, mais ne supportent pas les méthodes globales (en dehors des classes, traits ou interfaces). PhpUnitGen autorise les méthodes get ou set privées/protégées.

V-E - Assertions sur les résultats d'une méthode

PhpUnitGen apporte aussi des annotations pour générer des assertions simples :

1. <?php

2. class Employee {

3. private $phone;

4. /**

5. * Vérifie que la méthode ne retourne pas un résultat null.

6. * @PhpUnitGen\assertNotNull()

7. * Vérifie que la méthode retourne la chaîne de caractères '012-345-6789'.

8. * @PhpUnitGen\assertEquals("'0123456789'")

9. */

10. public function getCellphone(): string

11. {

12. return $this->phone;

13. }

14. }

Une annotation d'assertion se compose d'un paramètre optionnel qui décrit la valeur attendue de l'assertion PHPUnit.

- Il peut être n'importe quelle expression PHP.

- S’il n'est pas fourni, PhpUnitGen considérera que l'assertion n'a pas besoin de paramètre, comme assertTrue par exemple.

V-F - Paramètres de méthode

Si la méthode que vous voulez tester a besoin de paramètres, vous pouvez utiliser l'annotation params.

1. <?php

2. class Employee {

3. /**

4. * Appelle la méthode avec les paramètres, et effectue les assertions sur le résultat.

5. * @PhpUnitGen\params("'John'", "'0123456789'")

6. * @PhpUnitGen\assertNotNull()

7. * @PhpUnitGen\assertEquals("'John: 0123456789'")

8. */

9. public static function getEmployeeInfo(string $name, string $phone): string

10. {

11. return $name . ': ' . $phone;

12. }

13. }

Cette annotation fonctionne comme l'annotation construct, mais les paramètres ne sont pas fournis dans un tableau JSON.

V-G - Création de Mock

L'annotation mock vous permet de créer un mock, qui pourra être défini en tant que propriété de la classe de test ou juste en variable de méthode.

1. <?php

2. namespace Company;

3. /**

4. * Crée un mock de "\Company\Employee" et l'ajoute dans une propriété de classe "$employee".

5. * @PhpUnitGen\mock("\\Company\\Employee", "employee")

6. *

7. * Utilise le mock créé "$employee" à partir de $this dans le constructeur.

8. * @PhpUnitGen\construct(["$this->employee"])

9. */

10. class EmployeeCard {

11. public function __construct(Employee $employee) { /* du code PHP */ }

13. /**

14. * Crée un mock uniquement dans le test de la méthode.

15. * @PhpUnitGen\mock("\\DateTime", "date")

16. *

17. * Utilise le mock dans les tests.

18. * @PhpUnitGen\params("$date")

19. * @PhpUnitGen\assertFalse()

20. */

21. public function isExpired(\DateTime $date): bool { /* du code PHP */ }

22. }

VI - Remerciements

Nos remerciements à Guillaume SIGUI pour la mise au gabarit, et f-leb pour la relecture orthographique.