TUTORIEL PHP 
Automatiser les tests pour les applications PHP
PHP permet aux développeurs Web de créer des applications Web complexes : jusque-là, rien de nouveau. Cependant, les techniques pour écrire des tests automatisés pour des applications Web PHP ne sont pas bien connues. (05/04/2004)

(fourni par Direction PHP)

<< 1. Intro | 2. L'application
3. Description de l'application | 4. Au-dela des bases

J'ai construit le script d'automatisation en deux fonctions. La fonction main() lit les données du cas de test dans un fichier texte, envoie une valeur d'entrée à l'application Web PHP et examine la réponse. La fonction main() appelle une fonction resHasTarget() qui renvoie " TRUE " si certaines données d'entrée contiennent une chaîne témoin. Voici le contenu du fichier de cas de tests utilisé dans cet exemple :

0001:Anderson:Adam:
0002:Baker:Bob:
0003:Baker:bob@build.com:
0004:Chung:Kathy:deliberate fail
0005:De La Paz:Doug:


Chaque ligne de données représente un seul cas de test. Un identifiant de cas de test à 4-chiffres est suivi par une valeur d'entrée, puis par le résultat attendu, dit valeur témoin. Enfin, un commentaire facultatif. Ainsi, dans le cas test 0002, si nous soumettons "Baker", nous devrions voir "Bob" en réponse.

La fonction main() débute en assignant des valeurs aux variables pour l'adresse IP du serveur Web, le port sur lequel le serveur écoute, le chemin vers l'application PHP, et la méthode utilisée pour envoyer les données de l'utilisateur :
$ipAddress = '127.0.0.1';
$port = '80';
$page = '/PHP/simple.php';
$method = 'POST';


Parce que c'est une automatisation de tests, vous devrez connaître l'adresse IP du serveur Web qui héberge votre application PHP, et il devrait être normalement 127.0.0.1 (localhost), à moins que vous ne testiez sur un serveur distant. Le port 80 est le port HTTP par défaut, mais il peut être différent dans un environnement de tests. Les deux principales méthodes pour envoyer de l'information vers un serveur Web sont POST et GET. Rappelez-vous que votre application Web factice envoie des données en utilisant POST:

<form name="theForm" action="simple.php" method="POST">

Je discuterai de l'utilisation des requêtes GET plus tard. Ensuite, main() affiche quelques informations minimales dans l'en-tête de la feuille puis ouvre le fichier cas test pour lecture. La suite de tests lit le fichier de cas de tests, ligne par ligne :

$line = fgets($fp, 4096);
list($caseid, $input, $expected, $comment) = explode(":", $line);
$postData = 'lastname=' . urlencode($input);


Pour chaque ligne, nous analysons les 4 champs délimités par des caractères deux points, en utilisant la fonction explode(). L'utilisation des deux points pour délimiter les données de cas de test est arbitraire : en général, vous pouvez utiliser n'importe quel caractère, mais devez éviter d'utiliser des caractères qui apparaissent dans les valeurs des cas de test. Nous ajoutons la valeur d'entrée à la variable lastname en utilisant la fonction urlencode(). Cette dernière remplace les caractères qui pourraient être mal compris par le serveur Web : ils sont remplacés par leur séquence équivalente. Par exemple, un caractère '/' sera remplacé par une séquence %2F.

Après avoir lu l'identifiant du cas de test, le nom de famille à envoyer et la valeur attendue, la fonction resHasTarget() fait tout le travail :

if (resHasTarget($ipAddress, $port, $method, $page, $postData, $expected))
  echo "$caseid Pass input = " . str_pad($input, 12) . "expected =
$expected\n";
else
  echo "$caseid FAIL input = " . str_pad($input, 12) . "expected =
$expected\n";


La fonction resHasTarget() envoie les données vers l'application web PHP et vérifie si la réponse attendue est dans le flux réponse. Pour le cas test 0001, "lastname=Anderson" est envoyé à 127.0.0.1:80/PHP/simple.php et la réponse est examinée pour rechercher la présence de la chaîne témoin "Adam". Si "Adam" est trouvé, resHasTarget() renvoie TRUE et nous enregistrons le succès du test avec "pass", et sinon, nous notons son échec "fail".

Examinons à présent la fonction resHasTarget() qui fait réellement la plupart du travail. Nous commençons par créer une socket et ensuite l'utilisons pour se connecter à notre serveur Web :

$socket = socket_create(AF_INET, SOCK_STREAM, 0)
or die("Socket failed\n");


$connect = socket_connect($socket, $ipAddress, $port)
or die("Connect failed\n");


Les constantes AF_INET et SOCK_STREAM signifie que nous voulons utiliser la notation numérique des IP (i.e., 127.0.0.1) et une connexion TCP full-duplex. Il y a deux alternatives importantes à la famille de fonctions sockets. Le choix bas niveau est la famille de fonctions fsock(). Un choix de niveau supérieur est d'utiliser les classes dans la bibliothèque PEAR. J'ai programmé des sockets en utilisant les trois méthodes et j'ai trouvé que le choix de l'une d'entre elle est plus une question de style de programmation que de fonctionnalité. Après cela, nous nous connectons au serveur Web pour déterminer la taille des données qui seront envoyées :

$reqBody = $postData;
$contentLength = strlen($reqBody);


Le paramètre d'entrée $postData s'assure que nous avons formaté les données, sous la forme d'une séquence de valeurs et noms. Par exemple :

user=chris&age=25&job=tester

Ensuite, nous construisons les en-têtes HTTP que nous allons envoyer au serveur :

$send = $method . " " . $page . " HTTP/1.1\r\n";
$send .= "Host: localhost\r\n";
$send .= "Accept: */*\r\n";
$send .= "User-Agent: test.php test automation\r\n";
$send .= "Content-Type: application/x-www-form-urlencoded\r\n";
$send .= "Content-Length: " . $contentLength . "\r\n\r\n";
$send .= $reqBody;
$send .= "\r\n";


Une requête HTTP commence avec une ligne qui mentionne la méthode (e.g., POST, GET, HEAD), suivi par le chemin pour l'application PHP et la version HTTP. La ligne d'en-tête suivante doit préciser l'hôte à qui la requête doit être envoyée. Les deux lignes d'en-tête suivantes sont facultatives. L'en-tête 'Accept' dit au serveur quelles sortes de réponses sont valides : ici nous accepterons tout. L'en-tête 'User-Agent' est une formule de politesse pour que le serveur Web sache quel navigateur fait la requête. Les deux lignes d'en-tête suivantes sont nécessaires pour des requêtes de type POST. Content-Type dit au serveur quelle sorte de données arrive. 'application/x-www-form-urlencoded' est une formule magique qui signifie "données provenant d'un formulaire HTML".

L'en-tête 'Content-Length' est la taille des données POST. Remarquez que nous devons construire les données POST avant les en-têtes, c'est la raison pour laquelle nous pouvons spécifier la taille à ce niveau du programme. Remarquez également que l'en-tête 'Content-Length' est suivi par deux caractères de nouvelles lignes. Dans le cas d'un système Windows comme ici, 2 combinaisons de retours la ligne, suivi de nouvelles lignes. Finalement, nous plaçons les données POST dans la requête.

Maintenant nous sommes prêts à envoyer la requête HTTP au serveur, puis récupérer le flux réponse et l'examiner :

socket_write($socket, $send, strlen($send));

while ($receiveBuffer = socket_read($socket, 2048))
  {
  if (strpos($receiveBuffer, $target))
    {
    socket_close($socket);
    return TRUE;
    }
  }


La fonction socket_write() envoie la requête et associe la réponse au socket. Nous lisons la réponse par groupe de 2048 octets (c'est une taille arbitraire). Nous utilisons également strpos() pour voir si la chaîne témoin se trouve quelque part dans les 2048 octets. Si elle y est, nous fermons la socket et renvoyons TRUE. Si nous examinons la réponse entière et ne trouvons pas la chaîne témoin, nous renvoyons FALSE.

Il y a une astuce ici : il est possible qu'un bloc d'octets du flux réponse finisse au milieu de la cible, la coupant en deux parties. Si c'est le cas, vous ne trouverez pas la chaîne témoin, alors qu'elle est bien présente. En pratique ce n'est pas très courant et vous pouvez vous protéger de cette possibilité en augmentant le nombre d'octets lus par socket_read() afin de capturer la totalité de la réponse en un seul bloc.

En résumé, la clé pour automatiser le test des applications Web PHP est la capacité d'envoyer des lignes de données HTTP au serveur Web. PHP a une famille de fonctions socket qui facilite cela. Après avoir lu les informations des fichiers de cas de tests contenant les valeurs d'entrée et les valeurs téoin, vous envoyez l'entrée au serveur pour examiner la réponse pour la valeur attendue.

En Utilisant la Méthode GET
Dans les paragraphes précédents, nous supposons que l'application Web PHP testée envoie des données au serveur en utilisant la méthode POST. Qu'en est-il si l'application utilise GET ? Supposez que vous avez une application Web où l'utilisateur soumet un ID d'utilisateur et un mot de passe en utilisant GET. C'est sûr que c'est une mauvaise idée parce qu'avec GET, les données du formulaire sont annexées à la requête URL. Le fragment de code suivant montre comment envoyer une requête en utilisant GET :

// create socket
// connect

$send = "GET /PHP/form2.php?";
$send .= "userID=" . urlencode("root");
$send .= "&password=" . urlencode("secret");
$send .= " HTTP/1.1\r\n";
$send .= "Host: localhost\r\n";
$send .= "\r\n";

socket_write($socket, $send, strlen($send));

// read response


La première ligne de l'en-tête de la requête HTTP utilise GET et les données à envoyer sont annexées à l'URL en tant que chaîne de question utilisant le format name=value. Parce que les données de l'utilisateur sont liées à l'URL, il est particulièrement important d'utiliser la fonction urlencode() pour manipuler les caractères ennuyeux.

<< 1. Intro | 2. L'application
3. Description de l'application | 4. Au-dela des bases
 
Dr. James McCaffrey pour JDN Développeurs
 
Accueil | Haut de page