2015-11-02 1 views
2

Je travaille avec un framework interne où chaque exception est interceptée par un gestionnaire d'erreur et renvoyée dans une réponse d'erreur JSON appropriée, adaptée à une API RESTFul.comment faire PHPUnit cesser d'intercepter les exceptions?

Ensuite, j'ai une suite de tests, qui sont des tests API, qui testent principalement que l'API renvoie les bonnes réponses JSON avec les codes d'erreur attendus.

Pour chaque test, les variables globales sont modifiées (puis restaurées) pour émuler une requête HTTP différente. Je le fais de cette façon pour éviter la surcharge de faire des tests cURL (via Guzzle ou similaire), et provoquer dans l'environnement CLI, le code ne connaît pas l'URL du serveur.

<?php 
// ... example, part of a base ApiTestCase class: 

// Override globals (should be backed up by PHPUnit) 
$_SERVER['REQUEST_METHOD']  = $request->method; 
$_SERVER['QUERY_STRING']  = http_build_query($request->parameters); 
$_SERVER['PATH_INFO']   = $request->path; 
$_SERVER['REQUEST_URI']  = $request->path . ($_SERVER['QUERY_STRING'] ? '?' : '') . $_SERVER['QUERY_STRING']; 
$_SERVER['REQUEST_TIME']  = time(); 
$_SERVER['REQUEST_TIME_FLOAT'] = microtime(true); 
$_SERVER['HTTP_COOKIE']  = ''; 

// Set headers, cookies and parameters 
foreach ($request->headers as $k => $v) { 
    $_SERVER['HTTP_' . strtoupper(str_replace('-', '_', trim($k)))] = $v; 
} 
if ($_SERVER['HTTP_COOKIE']) { 
    $GLOBALS['_COOKIE'] = http_parse_cookie($_SERVER['HTTP_COOKIE']); 
} else { 
    $GLOBALS['_COOKIE'] = []; 
} 
$GLOBALS['_REQUEST'] = $request->parameters; 

$responseBody = $app->start(); 

$response->httpCode = http_response_code(); 
$response->body  = $responseBody ? @json_decode($responseBody) : null; 
$response->headers = headers_list(); 

(je sais que le changement GLOBALS cette façon est pas agréable et le cadre ne doit pas compter sur GLOBALS directement, mais je dois encore traiter avec le code existant.)

Puis vient le problème ici: lorsque j'essaie de tester les réponses aux erreurs JSON: PHPUnit intercepte l'exception lancée (avant le gestionnaire que j'ai mentionné au début), donc le framework n'a aucune chance de le convertir en JSON et de retourner la bonne réponse.

J'ai essayé de trouver quelque chose dans le manuel PHPUnit pour désactiver le gestionnaire d'erreur PHPUnit sans aucune chance.

Que puis-je faire dans ce cas? Merci

+0

Juste pour noter que la plus grande partie du code que vous avez cité ressemble probablement à une fonction 'setup()' dans votre classe de test phpUnit. De plus, notez que phpUnit a la capacité intégrée de restaurer les globals à leur état vierge après chaque test. Vous pouvez utiliser cela plutôt que de réinventer la roue. – Simba

+0

le code est juste un exemple, mais c'est vrai que PHPunit fait des sauvegardes globales – itsjavi

+0

@mjolnic Salut mec, j'ai le même problème ici. Avez-vous trouvé une résolution appropriée? – dKen

Répondre

0

Juste pour être clair, il semble que nous ne parlons pas d'attraper des exceptions ici; nous parlons d'utiliser PHP set_error_handler() pour intercepter une erreur fatale avant de terminer le programme. Cela traitera à la fois des erreurs et des exceptions non interceptées. Une chose que vous ne serez pas capable de faire est de laisser ces erreurs et exceptions passer à votre fonction de gestionnaire d'erreur - comme vous l'avez déjà constaté, phpUnit fait sa propre gestion des erreurs que vous ne pouvez pas ignorer (parce que c'est un peu fondamental pour le fonctionnement de phpUnit).

Ce que vous allez devoir faire est de dire à phpUnit quel genre d'exception ou d'erreur vous attendez; votre test passera ou échouera selon que l'erreur se produit. Vous ne lancerez pas le gestionnaire d'erreurs, mais en vérité, vous ne devriez pas avoir besoin de le faire; vous pouvez tester la fonction séparément si vous en avez besoin. Pour les conditions d'erreur, vous n'avez pas besoin de voir que le gestionnaire d'erreurs produit la bonne sortie à chaque fois, juste qu'une erreur se produit qui déclenchera le gestionnaire.

Pour les exceptions PHP régulières, vous pouvez utiliser l'annotation @expectedException de PHPUnit au-dessus de votre fonction de test, comme ceci:

/** 
* @expectedException YourExpectedExceptionClass 
*/ 
function testThisWillThrowAnException() { 
    .... 
} 

Si le code PHP devrait produire une erreur de PHP (par exemple une erreur, pas une exception) , alors vous utiliseriez la même idée, mais phpUnit fournit un nom de classe auxiliaire pour l'erreur: PHPUnit_Framework_Error. Donc, votre code ressemblera à ceci:

/** 
* @expectedException PHPUnit_Framework_Error 
*/ 
function testThisWillProduceAPHPError() { 
    .... 
} 

Dans les deux cas, votre test passera si l'erreur attendue/exception se produit.

Vous pouvez également tester des messages et des codes d'exception spécifiques, dans le cas où la classe d'exception ne constitue pas une information suffisante pour que vous sachiez si le test a fait ce que vous voulez qu'il fasse. Voir the phpUnit manual page for annotations pour plus d'informations.

+1

Merci, le fait est que je teste déjà ces exceptions dans les tests unitaires (qui testent le code source et le comportement) et que je ne voudrais pas dupliquer cela. Ce que j'essaie de faire ici est de tester la réponse finale: ce que les clients obtiennent réellement, ce qui ne semble pas possible dans PHPUnit sans faire appel à cURL, ce qui ralentit l'exécution des tests et ne permet pas de se moquer du code source ou source de données. – itsjavi

0

L'exemple ci-dessus est également correct, le mien fournit uniquement des exceptions comme des assertions et vous donne des informations sur le fonctionnement des exceptions. Cela vous permet également de tester les données fausses ou inncorectes et d'affirmer qu'elles sont incorrectes.

+0

Le point OP essaie de faire est que les exceptions sont déjà attrapées dans son application, et traitées là. Au moment où son API répond, toutes les exceptions sont converties en réponses JSON, et il veut vérifier que les réponses sont correctes. Ajouter plus de gestion des exceptions à ses tests ne traite que le symptôme, mais manque complètement le point et ne permet pas de tester la réponse JSON qui est le but. – dKen