|
|
|
|
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 )
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.
|
|
|
|
|
|