41 votes

comment tester un appel curl unitaire en php

Comment feriez-vous pour tester unement une implémentation curl?

   public function get() {
    $ch = curl_init($this->request->getUrl());

    curl_setopt($ch, CURLOPT_HEADER, false);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

    $result = curl_exec($ch);
    $code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    $type = curl_getinfo($ch, CURLINFO_CONTENT_TYPE);
    curl_close($ch);

    if (!strstr($type, 'application/json')) {
      throw new HttpResponseException('JSON response not found');
    }

    return new HttpResponse($code, $result);
  }
 

J'ai besoin de tester le type de contenu renvoyé afin qu'il puisse lever une exception.

53voto

David Harkness Points 16674

Comme l'a suggéré thomasrutter, créez une classe pour résumer l'utilisation des fonctions cURL.

 interface HttpRequest
{
    public function setOption($name, $value);
    public function execute();
    public function getInfo($name);
    public function close();
}

class CurlRequest implements HttpRequest
{
    private $handle = null;

    public function __construct($url) {
        $this->handle = curl_init($url);
    }

    public function setOption($name, $value) {
        curl_setopt($this->handle, $name, $value);
    }

    public function execute() {
        return curl_exec($this->handle);
    }

    public function getInfo($name) {
        return curl_getinfo($this->handle, $name);
    }

    public function close() {
        curl_close($this->handle);
    }
}
 

Vous pouvez maintenant tester en utilisant une maquette de l'interface HttpRequest sans invoquer aucune des fonctions cURL.

 public function testGetThrowsWhenContentTypeIsNotJson() {
    $http = $this->getMock('HttpRequest');
    $http->expects($this->any())
         ->method('getInfo')
         ->will($this->returnValue('not JSON'));
    $this->setExpectedException('HttpResponseException');
    // create class under test using $http instead of a real CurlRequest
    $fixture = new ClassUnderTest($http);
    $fixture->get();
}
 

Modifier Correction d'une simple erreur d'analyse PHP.

7voto

cweiske Points 13722

N'utilisez pas curl directement mais via un wrapper comme HTTP_Request2 de PEAR. Avec lui, vous avez la possibilité d'échanger le pilote de boucle avec un pilote simulé - idéal pour les tests unitaires.

3voto

Martin Büttner Points 26511

Je suis tombé sur cette question quand j'étais en train de tester une classe à l'aide de cURL moi-même. J'ai pris David Harkness conseils à cœur, et créé une interface pour le roulage. Cependant, le stub/maquette fonctionnalités fournies par PHPUnit n'était pas suffisant dans mon cas, j'ai donc ajouté mon propre stub de mise en œuvre de l'interface et mettre tout ça sur GitHub. Et parce que cette question se montre assez tôt sur Google lors de la recherche de ce problème, je pensais que j'allais poster ici, alors que les autres pourraient être en mesure de sauver l'effort.

Elle est ici.

Le référentiel du wiki contient une plutôt une documentation détaillée de la stub des capacités, mais ici, ils sont en court.

L'interface est un mappage 1:1 de PHP cURL fonctions, de sorte qu'il est devenu très facile de commencer à utiliser l'interface (tout simplement la main sur votre ClassUnderTest un exemple de mise en œuvre SAI_CurlInterface , puis de les appeler tous cURL fonctionne comme avant, mais que les méthodes de cette instance). La classe SAI_Curl implémente cette interface, simplement en déléguant à friser. Maintenant, si vous voulez tester l' ClassUnderTest vous pouvez donner un exemple d' SAI_CurlStub.

Le stub principalement atténue le problème que PHPUnit de simulacres et les talons ne peut pas renvoyé des données factices selon l'ancien appels de fonction (mais c'est de cette façon cURL fonctionne réellement - vous définissez vos options et de la réponse, le code d'erreur et cURL-info dépendent de ces options). Voici donc un petit exemple, montrant les capacités de réponses (pour les codes d'erreur et boucle d'informations, voir le wiki).

public function testGetData()
{
    $curl = new SAI_CurlStub();

    // Set up the CurlStub
    $defaultOptions = array(
        CURLOPT_URL => 'http://www.myserver.com'
    );
    $chromeOptions = array(
        CURLOPT_URL => 'http://www.myserver.com',
        CURLOPT_USERAGENT => 'Chrome/22.0.1207.1'
    );
    $safariOptions = array(
        CURLOPT_URL => 'http://www.myserver.com',
        CURLOPT_USERAGENT => 'Safari/537.1'
    );

    $curl->setResponse('fallback response');
    $curl->setResponse('default response from myserver.com'
                       $defaultOptions);
    $curl->setResponse('response for Chrome from myserver.com',
                       $chromeOptions);
    $curl->setResponse('response for Safari from myserver.com',
                       $safariOptions);

    $cut = new ClassUnderTest($curl);

    // Insert assertions to check whether $cut handles the
    // different responses correctly
    ...
}

Vous pouvez faire de votre réponse dépend d'une combinaison de cURL-options. Bien sûr, vous pouvez aller encore plus loin. Disons, par exemple, votre ClassUnderTest prend quelques données XML à partir d'un serveur et l'analyse (eh bien, vous devriez avoir deux classes distinctes pour ces tâches, mais supposons que ce pour notre exemple), et que vous voulez tester ce comportement. Vous pouvez télécharger la réponse XML manuellement, et vous avez votre test lire les données à partir du fichier et de le ranger dans la réponse. Alors vous savez exactement ce que les données sont là, et peut vérifier si c'est analysée correctement. Sinon, vous pouvez mettre en œuvre l' SAI_CurlInterface le chargement de toutes les réponses de votre système de fichiers tout de suite, mais la mise en œuvre est certainement un point de départ.

Au moment où je je suis en train d'écrire cette réponse, @SAI_CurlStub@ ne prend pas en charge cURL multi-lib fonctionnalités encore, mais j'ai l'intention de mettre en œuvre cela, aussi, à l'avenir.

J'espère que ce talon est d'aider toute personne qui veut l'unité de test cURL-classes dépendantes. N'hésitez pas à consulter et à utiliser les classes, ou de contribuer, bien sûr - c'est sur GitHub, après tout :). Aussi, je suis ouvert à toute critique constructive concernant la mise en œuvre et l'utilisation de l'interface et la stub.

2voto

thomasrutter Points 42905

Une approche consiste à remplacer l'interface que vous utilisez (dans ce cas, le curl_ fonctions) avec des feintes des versions d'eux-mêmes qui, de retour de certaines valeurs. Si vous utilisez l'une orientée objet library, ce serait plus facile parce que vous pouvez juste remplacer un objet factice qui a la même méthode pour les noms (et en effet, les cadres comme simpletest pouvez configurer objet factice méthodes facilement). Sinon, peut-être il ya quelques autres de la sorcellerie vous pouvez utiliser pour remplacer les fonctions intégrées avec des mannequins. Cette extension comprend override_function() qui ressemble à ce que vous auriez besoin, mais qui permettrait d'ajouter une autre dépendance.

Si vous voulez tester sans remplacement de la curl_ fonctions fictives versions, on dirait que vous aurez besoin de configurer un mannequin serveur qui sera de retour à un certain résultat, de sorte que vous pouvez tester la façon dont votre PHP, et son extension curl, poignées de résultat. Pour tester complètement, vous devez accéder à ce sur HTTP plutôt que, disons, un fichier local, parce que votre PHP dépend de l'existence d'un code de réponse HTTP, etc. Si vos tests nécessaire au bon fonctionnement d'un serveur HTTP.

D'ailleurs, PHP 5.4 comprendront son propre serveur web qui seraient utiles à cet effet. Sinon, vous pourriez mettre un script de test sur un serveur qui vous contrôle, ou de distribuer une simple configuration du serveur avec vos tests.

Si vous étiez réellement utiliser le serveur live pour vos tests, ce serait devenu moins d'une unité de test et plus d'un test d'intégration, parce que vous tester à la fois PHP et le serveur, et l'intégration entre les deux. Vous aussi manquer d'être en mesure de tester sur la demande de la façon dont votre code poignées de certaines défaillances.

-1voto

Robert Martin Points 5480

Dans votre test unitaire, demandez à request->getUrl() renvoyer l'URI d'un fichier local dont vous savez qu'il lèvera l'exception.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X