Tout d'abord, où en sont mes connaissances :
Tests unitaires sont celles qui testent un petit morceau de code (des méthodes uniques, le plus souvent).
Tests d'intégration sont ceux qui testent l'interaction entre plusieurs zones de code (qui, espérons-le, ont déjà leurs propres tests unitaires). Parfois, certaines parties du code à tester exigent que d'autres codes agissent d'une manière particulière. C'est là que les Mocks et les Stubs entrent en jeu. Ainsi, nous simulons/stubons une partie du code pour qu'elle agisse de manière très spécifique. Cela permet à notre test d'intégration de s'exécuter de manière prévisible sans effets secondaires.
Tous les tests doivent pouvoir être exécutés de manière autonome sans partage de données. Si le partage des données est nécessaire, c'est un signe que le système n'est pas assez découplé.
Ensuite, la situation à laquelle je suis confronté :
Lorsque l'on interagit avec une API externe (plus précisément, une API RESTful qui modifiera des données en direct avec une requête POST), je crois savoir que l'on peut (doit ?) simuler l'interaction avec cette API (ce qui est plus éloquent dans la rubrique cette réponse ) pour un test d'intégration. Je comprends également que nous pouvons tester en unité les composants individuels de l'interaction avec cette API (construction de la requête, analyse du résultat, lancement des erreurs, etc.) Ce que je ne comprends pas, c'est comment procéder.
Alors, finalement : Ma ou mes questions.
Comment puis-je tester mon interaction avec une API externe qui a des effets secondaires ?
Un exemple parfait est L'API de contenu de Google pour le shopping . Pour être en mesure d'effectuer la tâche en question, il faut une bonne dose de travail préparatoire, puis effectuer la requête proprement dite, et enfin analyser la valeur de retour. Une partie de ce travail est sans environnement "sandbox". .
Le code pour faire cela a généralement plusieurs couches d'abstraction, quelque chose comme :
<?php
class Request
{
public function setUrl(..){ /* ... */ }
public function setData(..){ /* ... */ }
public function setHeaders(..){ /* ... */ }
public function execute(..){
// Do some CURL request or some-such
}
public function wasSuccessful(){
// some test to see if the CURL request was successful
}
}
class GoogleAPIRequest
{
private $request;
abstract protected function getUrl();
abstract protected function getData();
public function __construct() {
$this->request = new Request();
$this->request->setUrl($this->getUrl());
$this->request->setData($this->getData());
$this->request->setHeaders($this->getHeaders());
}
public function doRequest() {
$this->request->execute();
}
public function wasSuccessful() {
return ($this->request->wasSuccessful() && $this->parseResult());
}
private function parseResult() {
// return false when result can't be parsed
}
protected function getHeaders() {
// return some GoogleAPI specific headers
}
}
class CreateSubAccountRequest extends GoogleAPIRequest
{
private $dataObject;
public function __construct($dataObject) {
parent::__construct();
$this->dataObject = $dataObject;
}
protected function getUrl() {
return "http://...";
}
protected function getData() {
return $this->dataObject->getSomeValue();
}
}
class aTest
{
public function testTheRequest() {
$dataObject = getSomeDataObject(..);
$request = new CreateSubAccountRequest($dataObject);
$request->doRequest();
$this->assertTrue($request->wasSuccessful());
}
}
?>
Note : Il s'agit d'un exemple PHP5 / PHPUnit.
Étant donné que testTheRequest
est la méthode appelée par la suite de tests, l'exemple exécutera une requête en direct.
Maintenant, cette requête en direct va (avec un peu de chance, si tout s'est bien passé) effectuer une requête POST qui a pour effet secondaire de modifier les données en direct.
Est-ce acceptable ? Quelles sont les alternatives possibles ? Je ne vois pas de moyen de simuler l'objet Request pour le test. Et même si je le faisais, cela impliquerait de mettre en place des résultats / points d'entrée pour chaque chemin de code possible que l'API de Google accepte (ce qui, dans ce cas, devrait être trouvé par essais et erreurs), mais me permettrait d'utiliser des fixtures.
Une autre extension se produit lorsque certaines demandes reposent sur le fait que certaines données sont déjà en direct. En reprenant l'exemple de l'API de contenu Google, pour ajouter un flux de données à un sous-compte, ce dernier doit déjà exister.
Une approche à laquelle je pense consiste à suivre les étapes suivantes ;
- Sur
testCreateAccount
- Créer un sous-compte
- Affirmer que le sous-compte a été créé
- Supprimer le sous-compte
- Avoir
testCreateDataFeed
dépendent detestCreateAccount
ne pas avoir d'erreurs- Sur
testCreateDataFeed
créer un nouveau compte - Créer le flux de données
- Affirmer que le flux de données a été créé
- Supprimer le flux de données
- Supprimer le sous-compte
- Sur
Cela soulève alors une autre question : comment puis-je tester la suppression des comptes / flux de données ? testCreateDataFeed
me semble sale - Que se passe-t-il si la création du flux de données échoue ? Le test échoue, donc le sous-compte n'est jamais supprimé... Je ne peux pas tester la suppression sans la création, alors dois-je écrire un autre test ( testDeleteAccount
) qui s'appuie sur testCreateAccount
avant de créer puis de supprimer son propre compte (car les données ne doivent pas être partagées entre les tests).
En résumé
- Comment puis-je tester l'interaction avec une API externe qui affecte les données en direct ?
- Comment puis-je simuler/supprimer des objets dans un test d'intégration lorsqu'ils sont cachés derrière des couches d'abstraction ?
- Que dois-je faire lorsqu'un test échoue et que les données en direct sont laissées dans un état incohérent ?
- Comment en code Comment dois-je m'y prendre pour faire tout cela ?
En rapport :
0 votes
Il s'agit de plusieurs questions générales, et non d'une question spécifique.
0 votes
Voir aussi : stackoverflow.com/questions/28069535/