Points de base
Cet article a été examiné par Younes Rafie. Merci à tous les pair de sitepoint pour avoir obtenu le contenu de sitepoint à son meilleur!
Je n'ai pas écrit de tests pour mon code au début. Comme beaucoup de gens, mon "test" écrit du code et rafraîchit la page. "Est-ce que ça a l'air bien?" Si je pense que c'est vrai, je vais continuer.
En fait, la plupart des travaux que j'ai faits sont pour les entreprises qui ne se soucient pas beaucoup d'autres formes de tests. Après des années d'expérience et des conseils judicieux de gens comme Chris Hartjes, j'ai vu la valeur des tests. Et j'apprends toujours à quoi ressemblent les bons tests.
J'ai récemment commencé à travailler sur des projets JavaScript qui incluent des observateurs de test groupés.
Il s'agit d'un merveilleux tutoriel vidéo avancé sur le développement de NodeJS axé sur les tests!
Dans le monde de JavaScript, il n'est pas rare de prétraiter le code source. Dans le monde JavaScript, les développeurs écrivent du code en utilisant une syntaxe non pris en charge, puis convertissent le code en syntaxe largement prise en charge, souvent en utilisant un outil appelé Babel.
Pour réduire le fardeau de l'appel des scripts de conversion, le projet BULERPLAY a commencé à inclure des scripts qui surveillent automatiquement les modifications des fichiers; puis appellent ces scripts.
Les projets sur lesquels j'ai travaillé ont adopté une approche similaire aux tests unitaires de relance. Lorsque je modifie les fichiers JavaScript, les fichiers sont convertis et les tests unitaires sont redimensionnés. De cette façon, je peux voir immédiatement si quelque chose est cassé.
Le code de ce tutoriel peut être trouvé sur GitHub. Je l'ai testé avec PHP 7.1.
J'ai commencé à mettre en place quelque chose de similaire pour Phpunit depuis que j'ai commencé à travailler sur ces projets. En fait, le premier projet que j'ai configuré le script PHPUnit Observer est un projet PHP qui prépare également des fichiers.
Après avoir ajouté un script de prétraitement à mon projet, tout a commencé:
composer require pre/short-closures
Ces scripts de prétraitement spécifiques me permettent de renommer les classes chargées automatiquement de PSR-4 (depuis path / to / file.php ⇒ path / to / file.pre) pour se opposer aux fonctionnalités qu'ils fournissent. J'ai donc ajouté ce qui suit à mon fichier composer.json:
"autoload": { "psr-4": { "App\": "src" } }, "autoload-dev": { "psr-4": { "App\Tests\": "tests" } }
C'est de composer.json
Ensuite, j'ai ajouté une classe pour générer une fonction contenant les détails de la session utilisateur actuelle:
namespace App; use Closure; class Session { private $user; public function __construct(array $user) { $this->user = $user; } public function closureWithUser(Closure $closure) { return () => { $closure($this->user); }; } }
Cela vient de src / session.pre
Pour vérifier si cela fonctionne, j'ai configuré un petit exemple de script:
require_once __DIR__ . "/vendor/autoload.php"; $session = new App\Session(["id" => 1]); $closure = ($user) => { print "user: " . $user["id"] . PHP_EOL; }; $closureWithUser = $session->closureWithUser($closure); $closureWithUser();
Cela vient de l'exemple.pre
… et parce que je veux utiliser de courtes fermetures dans les classes non PSR-4, j'ai également besoin de configurer un chargeur:
require_once __DIR__ . "/vendor/autoload.php"; Pre\Plugin\process(__DIR__ . "/example.pre");
Cela vient de Loader.php
Cette section de code est beaucoup pour illustrer un petit point. La classe de session a une méthode CLOSUREWITHUSER qui accepte une fermeture et en retourne une autre. Lorsqu'il est appelé, cette nouvelle fermeture appellera la fermeture d'origine, fournissant le tableau de session utilisateur en tant que paramètre.
Pour exécuter tout cela, tapez le terminal:
php loader.php
En tant que note latérale, ces préprocesseurs génèrent une syntaxe PHP efficace qui est assez belle. Cela ressemble à ceci:
$closure = function ($user) { print "user: " . $user["id"] . PHP_EOL; };
… et
public function closureWithUser(Closure $closure) { return [$closure = $closure ?? null, "fn" => function () use (&$closure) { $closure($this->user); }]["fn"]; }
Vous ne voudrez peut-être pas soumettre des fichiers PHP et PRE au référentiel. Pour ce faire, j'ai ajouté App / ** / *. Php et Examples.php à .gitignore.
Alors, comment tester cela? Commençons par installer phpunit:
composer require --dev phpunit/phpunit
Ensuite, nous devons créer un fichier de configuration:
<?xml version="1.0" encoding="UTF-8"?> <phpunit backupGlobals="false" backupStaticAttributes="false" bootstrap="vendor/autoload.php" colors="true" convertErrorsToExceptions="true" convertNoticesToExceptions="true" convertWarningsToExceptions="false" processIsolation="false" stopOnFailure="false" syntaxCheck="false" > <testsuites> <testsuite> <directory suffix="Test.php">tests</directory> </testsuite> </testsuites> <filter> <whitelist addUncoveredFilesFromWhitelist="true"> <directory suffix=".php">src</directory> </whitelist> </filter> </phpunit>
C'est de phpunit.xml
Si nous exécutons le fournisseur / bin / phpunit, cela fonctionnera. Mais nous n'en avons pas encore testé. Faisons-en un:
namespace App\Tests; use App\Session; use PHPUnit\Framework\TestCase; class SessionTest extends TestCase { public function testClosureIsDecorated() { $user = ["id" => 1]; $session = new Session($user); $expected = null; $closure = function($user) use (&$expected) { $expected = "user: " . $user["id"]; }; $closureWithUser = $session ->closureWithUser($closure); $closureWithUser(); $this->assertEquals("user: 1", $expected); } }
Cela provient de tests / sessiontest.php
Lorsque nous exécutons le fournisseur / bin / phpunit, un seul test passe. Ouais!
Jusqu'à présent, tout s'est bien passé. Nous avons écrit un petit code et des tests de ce morceau de code. Nous n'avons même pas à nous soucier du fonctionnement du prétraitement (une étape qu'un projet JavaScript).
Le problème commence lorsque nous essayons de vérifier la couverture du code:
vendor/bin/phpunit --coverage-html coverage
Au moment où nous avons testé la session, la couverture sera signalée. C'est une classe simple, nous avons donc obtenu une couverture à 100%. Mais si nous ajoutons une autre classe:
namespace App; class BlackBox { public function get($key) { return $GLOBALS[$key]; } }
Cela vient de SRC / BlackBox.Pre
Que se passe-t-il lorsque nous vérifions la couverture? Toujours à 100%.
Cela se produit parce que nous n'avons pas de tests chargeant BlackBox.pre, ce qui signifie qu'il n'est jamais compilé. Par conséquent, lorsque PHPUnit recherche un fichier PHP écrasé, il ne peut pas voir ce fichier pré-cours.
Créons un nouveau script pour créer tous les fichiers pré avant d'essayer d'exécuter le test:
composer require pre/short-closures
Cela provient des tests / bootstrap.php
Ici, nous créons 3 fonctions;
Nous devons remplacer le fichier bootstrap actuel dans phpunit.xml:
"autoload": { "psr-4": { "App\": "src" } }, "autoload-dev": { "psr-4": { "App\Tests\": "tests" } }
C'est de phpunit.xml
Maintenant, chaque fois que nous exécutons le test, ce script nettoyera et reconstruia d'abord tous les fichiers pré au fichier PHP. La couverture est correctement signalée et nous pouvons continuer notre heureux voyage…
Notre base de code est petite, mais elle n'a pas besoin d'être petite. Nous pouvons essayer ceci dans une vraie application et regretter immédiatement d'avoir à reconstruire le fichier chaque fois que nous voulons le tester.
Dans ce projet que j'ai mentionné, j'ai 101 fichiers pré. Juste pour exécuter ma suite de test unitaire (espérons-le rapide), cela nécessite beaucoup de prétraitement. Nous avons besoin d'un moyen de surveiller les changements et de reconstruire uniquement les pièces importantes. Tout d'abord, installons un observateur de fichiers:
namespace App; use Closure; class Session { private $user; public function __construct(array $user) { $this->user = $user; } public function closureWithUser(Closure $closure) { return () => { $closure($this->user); }; } }
Ensuite, créons un script de test:
require_once __DIR__ . "/vendor/autoload.php"; $session = new App\Session(["id" => 1]); $closure = ($user) => { print "user: " . $user["id"] . PHP_EOL; }; $closureWithUser = $session->closureWithUser($closure); $closureWithUser();
Cela provient des scripts / test de montre
Ce script crée un Symfony Finder (utilisé pour scanner nos dossiers SRC et tests). Nous avons défini un fichier de changement temporaire, mais ce n'est pas strictement requis pour ce que nous faisons. Nous utilisons ensuite une boucle infinie. ResourceWatcher a une méthode que nous pouvons utiliser pour voir si un fichier a été créé, modifié ou supprimé.
Nouveau, trouvons quels fichiers ont été modifiés et les reconstruisez:
require_once __DIR__ . "/vendor/autoload.php"; Pre\Plugin\process(__DIR__ . "/example.pre");
Cela provient des scripts / test de montre
Ce code est similaire à ce que nous faisons dans le fichier bootstrap, mais il ne s'applique qu'aux fichiers modifiés. Nous devons également relancer le test lorsque le fichier change:
php loader.php
Cela provient des scripts / test de montre
Nous introduisons plusieurs variables d'environnement. Vous pouvez gérer ces variables à votre goût, mais je préfère les ajouter au script compositeur:
$closure = function ($user) { print "user: " . $user["id"] . PHP_EOL; };
C'est de composer.json
App_cover n'est pas si important. Il indique simplement à l'observateur si le script contient une couverture de code. App_rebuild joue un rôle plus important: il contrôle si le fichier pré est reconstruit lorsque le fichier tests / bootstrap.php est chargé. Nous devons modifier le fichier afin que le fichier soit reconstruit uniquement à la demande:
public function closureWithUser(Closure $closure) { return [$closure = $closure ?? null, "fn" => function () use (&$closure) { $closure($this->user); }]["fn"]; }
Cela provient des tests / bootstrap.php
Nous devons également modifier le script Observer pour définir cette variable d'environnement avant d'inclure le code bootstrap. L'ensemble du script d'observateur ressemble à ceci:
composer require --dev phpunit/phpunit
Cela provient des scripts / test de montre
Maintenant, nous devrions être en mesure de le démarrer et d'exécuter nos tests chaque fois que le fichier pré-cours change ...
quelques choses à retenir (RAWR). Tout d'abord, vous avez besoin de scripts CHMOD X / * pour exécuter le script Observer. Deuxièmement, vous devez définir la configuration: {Process-Timeout: 0} (dans Composer.json), sinon l'observateur mourra après 300 secondes.
Cet observateur de test a également permis un effet secondaire frais: la possibilité d'utiliser un préprocesseur / conversion dans nos tests de phpunit. Si nous ajoutons du code aux tests / bootstrap.php:
composer require pre/short-closures
Cela provient des tests / bootstrap.php
… et nous permettons le prétraitement dans le fichier de test (pour pré, cela signifie le renommer à .pre). Ensuite, nous pouvons commencer à utiliser le même préprocesseur dans notre fichier de test:
"autoload": { "psr-4": { "App\": "src" } }, "autoload-dev": { "psr-4": { "App\Tests\": "tests" } }
Cela provient de tests / sessiontest.pre
Je ne peux pas croire que j'ai fait tellement de travail de préprocesseur avant d'essayer de créer un tel observateur de test. Cela prouve ce que nous pouvons apprendre des autres langues et cadres. Si je ne suis pas impliqué dans ces projets JavaScript, je peux continuer à reconstruire mes fichiers avant chaque test. nausée!
Cette méthode est-elle efficace pour vous? Il peut s'adapter à un serveur HTTP asynchrone ou à d'autres processus de longue durée. Veuillez nous dire ce que vous pensez dans les commentaires.
La configuration des observateurs de test de style JavaScript dans PHP implique plusieurs étapes. Tout d'abord, vous devez installer PHPUNIT et PHPUnit-watcher. PHPUnit est un cadre de test pour PHP qui fournit un moyen d'écrire des tests de code. Phpunit-watcher est un outil qui surveille votre code et exécute des tests PHPUnit lors de l'enregistrement des fichiers. Après avoir installé ces outils, vous pouvez configurer Phpunit-watcher pour surveiller votre code et exécuter automatiquement vos tests. Ce paramètre vous permet d'obtenir immédiatement des commentaires sur les modifications de code, ce qui peut vous aider à découvrir et à corriger les erreurs plus rapidement.
Il y a de nombreux avantages à utiliser des observateurs de test dans PHP. Il fournit des commentaires instantanés sur les modifications de code, ce qui peut vous aider à découvrir et à corriger les erreurs plus rapidement. Cela vous fait également gagner du temps car vous n'avez pas à exécuter le test manuellement après chaque changement de code. De plus, il vous encourage à rédiger des tests pour votre code, ce qui peut améliorer la qualité de votre code et faciliter la maintenance.
Oui, vous pouvez utiliser le code PHP dans les fonctions JavaScript, mais cela n'est pas recommandé. PHP est un langage côté serveur, tandis que JavaScript est un langage côté client. Cela signifie que le code PHP est exécuté sur le serveur avant l'envoi de la page au client, tandis que le code JavaScript est exécuté sur le client après la réception de la page. Par conséquent, si vous essayez d'utiliser du code PHP dans une fonction JavaScript, le code PHP sera exécuté avant la fonction JavaScript, ce qui peut conduire à des résultats inattendus.
CodeCection est un cadre de test pour PHP qui prend en charge les tests unitaires, les tests fonctionnels et les tests d'acceptation. Pour tester votre code PHP avec CodeCeception, vous devez d'abord installer CodeCeception et le configurer pour votre projet. Vous pouvez ensuite rédiger des tests pour votre code à l'aide de la syntaxe de CodeCection et exécuter vos tests à l'aide de l'outil de ligne de commande de codeceception.
Bien que techniquement, vous pouvez écrire du code PHP en JavaScript, cela n'est pas recommandé. PHP est un langage côté serveur, tandis que JavaScript est un langage côté client. Cela signifie que le code PHP est exécuté sur le serveur avant l'envoi de la page au client, tandis que le code JavaScript est exécuté sur le client après la réception de la page. Par conséquent, si vous essayez d'écrire du code PHP dans JavaScript, le code PHP sera exécuté avant le code JavaScript, ce qui peut conduire à des résultats inattendus. Au lieu de cela, il est préférable d'utiliser Ajax pour envoyer des données du client au serveur et vice versa.
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!