12
votes

Tests de l'unité PHP: est-il possible de tester une erreur fatale?

fwiw J'utilise SimpleTest 1.1alpha.

J'ai une classe singleton et je tiens à écrire un test unitaire qui garantit que la classe est un singleton en essayant d'instancier la classe (il dispose d'un constructeur privé).

Ceci provoque évidemment une erreur fatale:

Erreur fatale: appel à FrontController privé :: __ construire ()

Y a-t-il un moyen de "attraper" cette erreur fatale et de signaler un test réussi?


4 commentaires

Il n'y a pas d'unité dans un test simple;)


@Gordon I Voir Le jeu de mots, mais je ne comprends pas.


Peut-être Cette réponse peut l'expliquer


Les cadres de test unitaires d'Oldschool sont impropres à cela. Écrivez un PHPT pour ce test et mélangez-le dans un cas PHPUNIT / SimpleTest utilisant une regex sur la sortie.


3 Réponses :


13
votes

Non. L'erreur fatale empêche l'exécution du script.

Et il n'est pas vraiment nécessaire de tester un singleton de cette façon. Si vous insistez sur la vérification si le constructeur est privé, vous pouvez utiliser réflexionClass: getconstructor () < / a> xxx

Une autre chose à considérer est que les classes / objets singletons sont un obstacle à TTD car ils sont difficiles à moquer.


0 commentaires

3
votes

Vous pouvez utiliser un concept comme l'isolement du processus de phpunit.

Ceci signifie que le code de test sera exécuté dans un sous-processus de PHP. Cet exemple montre comment cela pourrait fonctionner. P>

<?php

// get the test code as string
$testcode = '<?php new '; // will cause a syntax error

// put it in a temporary file
$testfile = tmpfile();
file_put_contents($testfile, $testcode);

exec("php $tempfile", $output, $return_value);

// now you can process the scripts return value and output
// in case of an syntax error the return value is 255
switch($return_value) {
    case 0 :
        echo 'PASSED';
        break;
    default :
        echo 'FAILED ' . $output;

}

// clean up
unlink($testfile);


9 commentaires

En pratique, ce seulement fonctionne pour détecter les erreurs de syntaxe, car (1) un script ne survivra généralement pas isolé, (2) il est irréalisable de bootstrap une application entière comme celle-ci, (3) elle ne crée pas Un contexte de test / répétible, (4) de ne pas avoir que tout le contexte mis en place pourrait provoquer de fausses erreurs mortelles comme fonction non définie . Ainsi, au lieu d'exécuter PHP $ TEMPFILE Il est préférable d'exécuter PHP -NO-php-ini --Syntax-check $ tempfile . PHP.net/manual/fr/Feats.commandline.option.php


Pouvez-vous prouver que? Je ne pense pas si


Eh bien, il "fonctionne" dans la console parce que je vois l'erreur fatale. Le retour $ est toujours 255 pour les six erreurs non incroyables et toujours 0 sinon. Je pense avoir besoin d'un gestionnaire d'arrêt pour accéder au code d'erreur. - Quant à PHPUnit, même si je @RuninSeparateProcessez un seul test causant une erreur fatale, il apparaît toujours comme un «E». - Votre idée est intéressante et je vous ai déjà plongé. Mais pour le faire fonctionner, je pense que je dois creuser en phpunit et écrire un patch ou un plugin. Je me demande pourquoi personne ne l'a fait auparavant. Est-il déraisonnable de s'attendre à ce que un script échoue?


Maintenant, j'ai eu vos préoccupations. Va jouer avec PHPUnit un peu, écrivez probablement du code et vous donnera un retour ..


J'ai trouvé qu'il y a une isolation personnalisable Modèle . Nous avons besoin de register_shutdown_function ('__ phpunit_shutdown', $ test, $ résultat) . __ phpunit_shutdown ($ test, $ résultat) (en cas d'erreur) imprime uniquement une matrice sérialisée comme d'habitude, mais avec une touche ajoutée ERROR_GET_LAST () . Ensuite, nous pouvons ajouter une prise en charge d'un @ExpecectedhutDownError à partir de phpunit_util_php :: runtestjob , qui appellerait processchildresult avec des arguments docompu (principalement stardr = '').


Belle recherche! Malheureusement, le nom de fichier du modèle est codé dur dans le code source. De plus, le @ExpectedhutDownError devrait être implémenté. Nous aurions besoin de Fork PHPUnit afin de produire le changement (ou je manque quelque chose?)


Le modèle d'isolation est personnalisable Par défaut . - Le reste est difficile à faire de Userland. Nous mettrions une classe au milieu de phpunit_util_php et ses descendants ( ..._ par défaut et ..._ windows ) pour remplacer runtestjob comme indiqué ci-dessus. Ensuite, à partir de la classe de cas d'essai, nous remplacerions exécuter de sorte que ici , nous pouvons instancier notre classe moyenne.


Si vous le souhaitez, créons une fourchette! (... et discutez des détails là). Pensant que l'idée est bonne et que cela ne nécessitera pas trop de changements (et de travailler).


Laissez-nous Continuez cette discussion en chat .



5
votes

Voici un extrait de code complet de la réponse de MCLL afin que les gens ne doivent pas avoir à traverser les docs ... xxx


0 commentaires