Testes automáticos para webservices Restful, em PHP

Testes unitários é uma ferramenta essencial para manter a qualidade do código e garantir que esteja tudo funcionando entre manutenções e upgrades. Se você não aplica, deveria :)

O fato é que geralmente testamos a aplicação “por dentro”,  com testes unitários para as classes e methodos dessas, mas na construção de um webservice pode ser interessante testar a aplicação “por fora”, realmente acessando a API com entradas válidas e inválidas para garantir que esteja respondendo bem às chamadas de clientes com os devidos cabeçalhos (Content-Type, Response Code e Message, etc) e o conteúdo em si esta correto. Teste de integração e outros são comumente negligenciados (inclusive por mim…).

Com isto em mente preparei um pequena classe em PHP, parte do pacote RestServer: a RestClient. É uma classe de uso geral para acesso HTTP através de cURL, pensando em testes para APIs de webservices.  O uso é simples, pode ser ver no exemplo/teste, veja por exemplo com atualizar o twitter:

<? 

$twitter = RestClient::post(
“http://twitter.com/statuses/update.json”
,array(“status”=>”Working with RestClient from RestServer!”)
,”username”
,”password”);
 

var_dump($twitter->getResponse());
var_dump($twitter->getResponseCode());
var_dump($twitter->getResponseMessage());
var_dump($twitter->getResponseContentType());

 ?>

 Você pode então combina-la com sua suite testes favorita (ou escrever na mão, se for chato) para testar sua API, veja partes dos testes do IdeasWall.org :

// Authorized access should be forbidden
$http = RestClient::get($base.”/ideas.json”);
if($http->getResponseCode() != 401) {
echo “Unauthorized access: Wrong response code\n”;
echo $http->getResponseCode().”\n”;
return false;
}

if($http->getResponse() != “Unauthorized”) {
echo “Unauthorized access: Wrong response\n”;
echo $http->getResponse().”\n”;
return false;
}

 // Will now create an idea , should create
$http = RestClient::post($base.”/ideas.json”,array(“idea”=>”I Rock”,”tags”=>”test”,”priori”=>”1″),”diogok”,”123″);
if($http->getResponseCode() != 201) {
echo “Create idea: not created.n”;
echo $http->getResponseCode().”\n”;
echo $http->getResponse().”\n”;
return false;
}
$ideaJson = $http->getResponse(); // This is the idea created;
$idea = Zend_JSon::decode($ideaJson,Zend_Json::TYPE_OBJECT);
if($idea->idea != “I Rock”) {
echo “Idea not created properly: Wrong idea\n”;
var_dump($idea);
return false;
}

// save map
$http = RestClient::post($base.”/ideas/”.$id.”/map.json”,array(“x”=>100,”y”=>200),”diogok”,”123″);
if($http->getResponseCode() != 200) {
echo “Erro at save map\m”;
echo $http->getResponseCode().”\n”;
echo $http->getResponse().”\n”;
return false;
}

$ideaJson = $http->getResponse(); // This is the idea updated;
$idea = Zend_JSon::decode($ideaJson,Zend_Json::TYPE_OBJECT);

if($idea->map->x != “100” || $idea->map->y != “200”) {
echo “Error in return idea map\n”;
var_dump($idea);
return false;
}

Claro que há muitas linha no arquivo de teste, mas deu para entender.