2009-08-28 7 views
30

Essentiellement j'ai une méthode d'une classe appelée killProgram, qui est destinée à envoyer une redirection hTTP, puis à tuer PHP.Comment utilisez-vous PHPUnit pour tester une fonction si cette fonction est censée tuer PHP?

Comment suis-je supposé tester cela? Quand je lance phpunit, il ne retourne rien pour ce test et se ferme complètement.

En ce moment je considère avoir la fonction killProgram jeter une exception qui ne devrait pas être traitée, ce qui me permettrait d'affirmer qu'une exception a été levée.

Y a-t-il un meilleur moyen?

Répondre

22

Comme tous les tests sont exécutés par le même processus de PHPUnit, si vous utilisez la sortie/die dans votre code PHP, vous tuerez tout - comme vous avez remarqué ^^

Donc, vous devez trouver une autre solution, oui - comme retourner au lieu de mourir; ou en lançant une exception (vous pouvez tester si un code testé a déclenché une exception attendue).

Peut-être PHPUnit 3.4 et il est --process-isolation commutateur (voir Optionally execute each test using a separate PHP process) pourrait aide (de ne pas avoir tout mourir), mais vous toujours pas en mesure d'obtenir le résultat du test, si PHPUnit ne récupère le contrôle.

J'ai eu ce problème plusieurs fois; résolu en retournant au lieu de mourir - même revenant plusieurs fois, si nécessaire, de revenir "assez haut" dans la pile d'appel ^^
En fin de compte, je suppose que je n'ai plus de "mourir" dans mon application ... C'est probablement mieux, en pensant à MVC, btw.

+0

Oui, en ce moment j'ai décidé de lancer une exception. Le problème est mon gestionnaire d'exceptions par défaut est destiné à appeler cette fonction, donc je dois créer une nouvelle exception appelée killProgramException que mon gestionnaire d'exception ignore. Genre de hacky –

7

Je sais que vous avez déjà accepté une réponse pour cela et il est une vieille question, mais je me dis que cela pourrait être utile pour quelqu'un, ce qui se passe ici:

Au lieu d'utiliser die(), vous pouvez utiliser throw new RuntimeException() (ou une classe d'exception de votre choix), qui va également arrêter l'exécution du programme (bien que d'une manière différente) et utiliser setExpectedException() de PHPUnit pour l'attraper. Si vous voulez que votre script à die() lorsque cette exception est rencontrée, l'impression absolument rien au niveau de l'utilisateur, jetez un oeil à set_exception_handler(). Plus précisément, je pense à un scénario dans lequel vous placeriez le set_exception_handler() -call dans un fichier d'amorçage que les tests n'utiliseraient pas, de sorte que le gestionnaire ne se déclenchera pas, quel que soit le scénario, donc rien n'interfère avec la gestion des exceptions natives de PHPUnit.

+3

Aime quand je poste un vieux répond à ma question. – stefgosselin

+0

cette réponse suggère fondamentalement d'utiliser des exceptions comme structures de contrôle de flux, ce qui n'est généralement pas souhaitable. –

13

Il n'est pas nécessaire de changer le code juste pour pouvoir le tester, vous pouvez simplement utiliser set_exit_overload() (fourni par test_helpers du même auteur que PHPUnit).

+1

Lien pour les paresseux: https://github.com/php-test-helpers/php-test-helpers (Notez qu'il s'agit d'une extension PHP que vous devez activer dans votre php.ini) –

+1

Note: Ce projet est n'est plus maintenu (depuis 2014). – amphetamachine

3

Cela concerne l'ensemble des problèmes que j'ai rencontrés pour obtenir un code hérité pour passer un test. Donc, je suis venu avec une classe testable comme ça ...

class Testable { 
    static function exitphp() { 
     if (defined('UNIT_TESTING')) { 
     throw new TestingPhpExitException(); 
     } else { 
     exit(); 
     } 
    } 
} 

Maintenant, je remplace simplement les appels à quitter() testables :: exitphp().

Si c'est sous test, je définis simplement UNIT_TESTING, en production je ne le fais pas. On dirait un simple simulacre.

+0

IMO, c'est très élégant. Je vous remercie. –

+1

cela pourrait sembler agréable au début, mais cela change le comportement du programme juste pour le plaisir de tester, ce qui ne serait pas agréable à la fin IMHO –

16

C'est évidemment une vieille question mais ma suggestion serait de déplacer le code die() dans une méthode séparée que vous pouvez alors mocker.

À titre d'exemple, au lieu d'avoir ceci:

class SomeClass 
{ 
    public function do() 
    { 
     exit(1); 
     // or 
     die('Message'); 
    } 
} 

faire ceci:

class SomeClass 
{ 
    public function do() 
    { 
     $this->terminate(123); 
     // or 
     $this->terminate('Message'); 
    } 

    protected function terminate($code = 0) 
    { 
     exit($code); 
    } 

    // or 
    protected function terminate($message = '') 
    { 
     die($message); 
    } 
} 

De cette façon, vous pouvez facilement se moquer de la méthode terminate et vous n'avez pas à vous soucier de la script se terminant sans que vous puissiez l'attraper.

Votre test ressemblerait à quelque chose comme ceci:

class SomeClassTest extends \PHPUnit_Framework_TestCase 
{ 

    /** 
    * @expectedExceptionCode 123 
    */ 
    public function testDoFail() 
    { 
     $mock = $this->getMock('SomeClass'); 
     $mock->expects($this->any()) 
      ->method('terminate') 
      ->will($this->returnCallback(function($code) { 
       throw new \Exception($code); 
      })); 

     // run to fail 
     $mock->do(); 
    } 
} 

Je ne l'ai pas testé le code, mais devrait être assez proche d'un état de fonctionnement.

Questions connexes