Guide important pour les tests d'API Rest et RestAssured

Dans ce tutoriel exhaustif Rest Assured, nous allons apprendre le Restez les tests API en profondeur, l'automatisation des tests API avec Rest Assured dans une approche modulaire

Qu'est-ce que RestAssured et son utilisation

Rest Assured est une technologie open source très largement utilisée pour les tests d'automatisation des API REST, elle est basée sur une bibliothèque basée sur Java.

Rest Assured interagit avec l'API Rest dans un mode client sans tête, nous pouvons améliorer la même requête en ajoutant différentes couches pour former la requête et créer une requête HTTP via différents verbes HTTPS sur le serveur.

La bibliothèque intégrée Rest Assured fournit d'énormes méthodes et utilitaires pour effectuer la validation de la réponse reçue du serveur, comme le message d'état, le code d'état et le corps de la réponse.

Cette série complète de didacticiels Rest Assured pour les tests d'automatisation des API REST comprend les sujets suivants:

RestAssured - Le test API du tutoriel reste assuré
Reste assuré l'automatisation des API

Mise en route: Configuration de restAssured avec l'outil de construction, c'est-à-dire Maven / gradle

ÉTAPE 1: Si vous travaillez avec maven, ajoutez simplement la dépendance suivante dans pom.xml (vous pouvez également choisir une autre version):

Pour démarrer avec REST Assured, ajoutez simplement la dépendance à votre projet. 


    io. soyez assuré
    repos assuré
    4.3.0
    tester

Si vous travaillez avec gradle, ajoutez simplement ce qui suit dans build.gradle (encore une fois, vous pouvez également choisir une autre version):

groupe testCompile: 'io.rest-assuré', nom: 'repos-assuré', version: '4.3.0'

ÉTAPE 2: REST Assured peut être intégré et utilisé très facilement avec les frameworks de test unitaires existants, c'est-à-dire Testng, JUnit

Ici, nous utilisons testNg selon le cadre de test unitaire.

Une fois les bibliothèques de Rest Assured importées, nous devons ajouter les importations statiques suivantes à nos classes de test:

import statique io.restassured.RestAssured. *;

import statique org.hamcrest.Matchers. *;

NOTE: Dans ce but d'apprentissage à venir, nous testerons l'API Ergast Developer, qui peuvent être trouvés ici. Cette API fournit des données historiques relatives aux courses de Formule 1, aux pilotes, aux circuits, etc.

Familiarité avec la syntaxe:

Rest Assured prend en charge le format BDD (Syntaxe de Gherkin) pour écrire les scripts de test, c'est-à-dire au format donné / quand / alors / et, nous supposons que vous avez une compréhension de la syntaxe BDD / gherkin, sinon nous suggérons de passer 30 minutes de temps pour comprendre ce qu'est BDD (Syntaxe de Gherkin) et comment ça marche et c'est très basique.

T-01: Notre 1er script qui valide essentiellement le nombre de circuits en F1 en 2017 en utilisant cette API (http://ergast.com/api/f1/2017/circuits.json)

@Test (description = "Nombre de circuits dans la saison 2017 devrait être de 20") public void validatingNumberOfCircuits () {given (). When (). Get ("http://ergast.com/api/f1/2017/circuits. json "). then (). assertThat (). body ("MRData.CircuitTable.Circuits.circuitId", hasSize (20)); }

Validation de la réponse de l'API Rest :

1. Capture la réponse JSON de la requête API.

2. Requêtes pour circuitId à l'aide de l'expression GPath «MRData.CircuitTable.Circuits.circuitId»

3. Vérifie que la collection d'éléments circuitId a une taille de 20

Ici, nous utilisons Matchers Hamcrest pour diverses validations telles que

Il existe diverses autres méthodes utiles pour effectuer certaines validations.

Vous pouvez en outre vous référer à la documentation de la bibliothèque Hamcrest pour une liste complète des matchers et des méthodes.

Validation du code de réponse:

donné (). when (). get ("http://ergast.com/api/f1/2017/circuits.json") .then (). assertThat (). statusCode (200);

Validation du type de contenu

donné (). when (). get ("http://ergast.com/api/f1/2017/circuits.json") .then (). assertThat (). contentType (ContentType.JSON);

Validation de l'en-tête "Content-Length"

donné (). when (). get ("http://ergast.com/api/f1/2017/circuits.json") .then (). assertThat (). header (" Content-Length ", equalTo (" 4551 "));

Validation multiple en un seul test comme (en utilisant les méthodes et ()):

@Test (description = "Le nombre de circuits dans la saison 2017 devrait être de 20")
    public void validatingNumberOfCircuits () {
        donné (). when (). get ("http://ergast.com/api/f1/2017/circuits.json") .then (). assertThat (). header ("Content-Length", equalTo (" 4551 ")). Et (). StatusCode (200);
    }

Validation de l'élément / attribut du corps de la réponse:

Nous pouvons utiliser JsonPath pour récupérer la valeur des attributs json et mettre l'assertion en utilisant TestNg

@Test (description = "Validation du nom de la série qui est f1")
    public void validatingSeriesName () {
        // Convertir ResponseBody en chaîne
        String responseBody = given (). When (). Get ("http://ergast.com/api/f1/2017/circuits.json") .getBody (). AsString ();
        // Créer un objet JsonPath en passant le corps de la réponse sous forme de chaîne
        JsonPath resJson = nouveau JsonPath (responseBody);
        // Récupère la série de valeurs d'attribut sous MRData
        Chaîne seriesName = resJson.getString ("MRData.series");
        // Assertion TestNg de l'utilisateur
        Assert.assertEquals ("f1", nomSérie);
    }

De la même manière, nous pourrions obtenir la valeur de la réponse XML en utilisant XMLPath. Ici, nous travaillons avec JSON, nous avons donc utilisé ici JSonPath

Les API RESTful ne prennent en charge que deux types de paramètres:

A. Paramètres de requête: Ici, les paramètres sont ajoutés à la fin du point de terminaison de l'API et peuvent être identifiés par le point d'interrogation et forment une paire clé / valeur telle que 

https://www.google.com/search?q=https://www.wikipedia.org/

Ici, dans l'API ci-dessus 'q' est le paramètre et 'https://www.wikipedia.org/' est la valeur de ce paramètre, si nous recherchons 'QUELQUE CHOSE_ELSE_TEXT'nous pourrions remplacer la valeur du paramètre 'q' avec »QUELQUE CHOSE_ELSE_TEXT'à la place de https://www.wikipedia.org/.

B. Paramètres du chemin: Ce sont la partie du point de terminaison de l'API RESTful. 

par exemple. endpoint que nous avons utilisé précédemment: http://ergast.com/api/f1/2017/circuits.json, ici «2017» est une valeur de paramètre de chemin.

Pour obtenir un résultat pour l'année 2016 nous pourrions remplacer 2017 par 2016 puis l'API donnera le corps de la réponse pour 2016.

Tests utilisant les paramètres de chemin pour RestAssured

@Test (description = "Validation du nombre de circuits à l'aide des paramètres de chemin")
    public void testWithPathParams () {
        String seasonNumber = "2017";
       String responseBody = given (). PathParam ("season", seasonNumber) .when (). Get ("http://ergast.com/api/f1/{season}/circuits.json") .getBody (). AsString ();
        // Créer un objet JsonPath en passant le corps de la réponse sous forme de chaîne
        JsonPath resJson = nouveau JsonPath (responseBody);
        // Récupère la série de valeurs d'attribut sous MRData
        Chaîne seriesName = resJson.getString ("MRData.series");
        // Assertion TestNg de l'utilisateur
        Assert.assertEquals ("f1", nomSérie);
    }

Tests utilisant les paramètres de requête pour RestAssured

@Test (description = "Validation de la recherche Google à l'aide des paramètres de requête")
    public void testWithPathParams () {
        String searchItem = "https://www.wikipedia.org/";
  given (). queryParam ("q", searchItem) .when (). get ("https://www.google.com/search") .then (). assertThat (). statusCode (200);
    }

Tests de paramétrage:

Nous pouvons faire des tests basés sur les données (c'est-à-dire que le même script de test sera exécuté plusieurs fois avec différents ensembles de données d'entrée et fournira différentes données de sortie) en utilisant Rest Assured 

ÉTAPE 1: Création d'un fournisseur de données de test.

ÉTAPE 2: utilisez le fournisseur de données dans le script de test.

@DataProvider (nom = "saisonsAndRaceNumbers")
    Objet public [] [] testDataFeed () {
        retourner un nouvel objet [] [] {
                {"2017", 20},
                {"2016", 21}
        };
    }
@Test (description = "Validation du nombre de circuits dans différentes saisons", dataProvider = "saisonsAndRaceNombres") public void circuitNumberValidation (String seasonYear, int raceNumbers) {given ().pathParam ("season", seasonYear) .when (). get ("http://ergast.com/api/f1/{saison}/circuits.json "). then (). assertThat (). body (" MRData.CircuitTable.Circuits.circuitId ", hasSize (nombres de course)); }

Utilisation de paramètres à valeurs multiples avec RestAssured 

Les paramètres multi-valeurs sont les paramètres qui ont plus d'une valeur par nom de paramètre (c'est-à-dire une liste de valeurs par paramKey), nous pouvons les traiter comme ci-dessous:

donné (). param ("paramKey", "paramValue1", "paramaValue2"). when (). get ("URL API");

Ou nous pourrions préparer une liste et passer la liste comme valeur de paramKey comme:

liste paramValue = nouveau nouveau ArrayList ();
paramValue.add ("paramvalue1");
paramValue.add ("paramvalue2);
donné (). param ("paramKey", paramValue) .when (). get ("URL API");
Travailler avec des cookies avec RestAssured 
donné (). cookie ("cookieK", "cookieVal"). when (). get ("URL API");

Or 

Nous pouvons également spécifier ici un cookie à valeurs multiples comme:

donné (). cookie ("cookieK", "cookieVal1", "cookieVal2"). when (). get ("URL API");

Travailler avec les en-têtes:

Nous pouvons spécifier dans une requête en utilisant des en-têtes / en-têtes comme:

donné (). header ("headerK1", "headerValue1"). header ("headerK2", "headerValue2"). when (). get ("API URL");

Travailler avec contentType:

donné (). contentType ("application / json"). when (). get ("URL API");

Or 

donné (). contentType (ContentType.JSON) .when (). get ();

Mesurer le temps de réponse:

long timeDurationInSeconds = get («URL API»). timeIn (SECONDS);

Authentification de l'API Rest

REST assuré prend en charge différents schémas d'authentification, par exemple OAuth, digest, certificat, formulaire et authentification de base préemptive. Nous pouvons soit définir l'authentification pour chaque demande 

voici un exemple de demande utilisant le même:

donné (). auth (). basic ("uName", "pwd"). when (). get ("URL") ..

D'autre part l'authentification et définie dans l'approche ci-dessous pour les requêtes HTTP:

RestAssured.authentication = basic ("uName", "pwd");

Types AUTH de base:

Il existe deux types d'authentification de base, «préemptive» et «authentification de base par jeton contesté».

Auth de base préemptive:

Cela enverra le justificatif d'authentification de base avant même que le serveur ne donne une réponse non autorisée dans certaines situations avec le déclenchement de la demande, réduisant ainsi la surcharge de l'établissement d'une connexion supplémentaire. Il s'agit généralement de situations qui se produisent principalement à moins que nous ne testions la capacité des serveurs à contester. 

Par exemple.

donné (). auth (). preemptive (). basic ("uName", "pwd"). when (). get ("URL"). then (). statusCode (200);

Authentification de base contestée

D'autre part, «authentification de base contestée», REST Assured ne fournira pas les informations d'identification à moins que le serveur ne l'ait explicitement demandé, c'est-à-dire que le serveur envoie la réponse non autorisée. Après cette réponse non autorisée, Rest-Assured envoie une autre requête au serveur qui est Auth.

donné (). auth (). basic ("uName", "pwd"). when (). get ("URL"). then (). statusCode (200);

Authentification Digest

Pour le moment, seule une «authentification condensée contestée» est envisagée. par exemple:

donné (). auth (). digest ("uName", "pwd"). when (). get ("URL"). then (). statusCode (200); 

Authentification par formulaire

Nous pourrions y parvenir principalement dans 3 approches différentes en fonction de l'application / des scénarios:

L'authentification par formulaire est l'une des plus populaires sur Internet : un utilisateur saisit ses informations d'identification, c'est-à-dire son nom d'utilisateur et son mot de passe via une page Web et se connecte au système. Cela pourrait être résolu en utilisant ceci 

donné (). auth (). form ("uName", "pWd").
quand (). get ("URL");
puis (). statusCode (200);

Bien que cela puisse ne pas fonctionner, c'est optimal et cela peut réussir ou échouer en fonction de la complexité de la page Web. Une meilleure option consiste à fournir ces détails lors de la configuration de l'authentification par formulaire dans l'approche ci-dessous:

given (). auth (). form ("uName", "pwd", new FormAuthConfig ("/ 'mentionne ici le nom de l'action du formulaire qui fait partie du code de la page html sous la balise form" "," uName "," pwd ")). when (). get (" URL "). then (). statusCode (200);

Dans cette approche, REST Assured en interne n'aura pas besoin de déclencher une demande supplémentaire et d'analyser la page Web. 

Si vous utilisez la sécurité Spring par défaut, alors un FormAuthConfig prédéfini est déclenché.

donné (). auth (). form ("uName", "Pwd", FormAuthConfig.springSecurity ()). when (). get ("URL"). then (). statusCode (200);

REMARQUE: Si nous voulons envoyer des données d'entrée supplémentaires avec l'authentification du formulaire, nous pouvons écrire ce qui suit:

donné (). auth (). form ("uName", "pwd", formAuthConfig (). withAdditionalFields ("firstInputField", "secondInputField"). ..

CSRF:

CSRF est l'acronyme de Cross-site request forgery.

De nos jours, il est très courant que le serveur fournisse un jeton CSRF avec la réponse pour éviter les attaques de sécurité CSRF. REST Assured prend en charge cela en utilisant un analyseur automatique et en fournissant un jeton CSRF. 

Afin de réaliser ce REST Assuré besoin de faire une demande supplémentaire et d'analyser (quelques positions) du site.

Nous pouvons activer le support CSRF en écrivant le code ci-dessous:

donné (). auth (). form ("uName", "pwd", formAuthConfig (). withAutoDetectionOfCsrf ()). when (). get ("URL"). then (). statusCode (200);

En plus d'aider REST Assured et de rendre l'analyse plus impeccable et robuste, nous pouvons fournir le nom du champ CSRF (ici, nous supposons que nous utilisons les valeurs par défaut de Spring Security et que nous pourrions utiliser springSecurity FormAuthConfig prédéfini):

donné (). auth (). form ("uName", "pwd", springSecurity (). withCsrfFieldName ("_ csrf")). when (). get ("URL"). then (). statusCode (200);

Par défaut, la valeur CSRF est passée en tant que paramètre de formulaire avec la requête, mais nous pouvons configurer pour l'envoyer en tant qu'en-tête si cela est nécessaire comme ci-dessous:

donné (). auth (). form ("uName", "pwd", springSecurity (). withCsrfFieldName ("_ csrf"). sendCsrfTokenAsHeader ()). when (). get ("URL"). then (). statusCode (200);

OAuth 1:

OAuth 1 nécessite que Scribe soit dans le chemin de classe. Pour utiliser l'authentification oAuth 1, nous pouvons faire:

donné (). auth (). oauth (..). when (). ..

OAuth 2:

donné (). auth (). oauth2 (accessToken) .when (). ..

Dans l'approche ci-dessus, le jeton d'accès OAuth2 sera considéré dans un en-tête. Pour être plus explicite, nous pouvons également faire:

donné (). auth (). preemptive (). oauth2 (accessToken) .when (). ..

Passer un fichier, un tableau d'octets, un flux d'entrée ou du texte dans la requête:

Lors de l'envoi de grandes quantités de données au serveur, il est généralement courant d'utiliser la technique des données de formulaire en plusieurs parties. Rest Assured fournit des méthodes appelées multiPart qui nous permettent de spécifier un fichier, un tableau d'octets, un flux d'entrée ou un texte à télécharger. 

donné (). multiPart (nouveau fichier ("/ File_Path")). when (). post ("/ upload");

Création de demande POST avec Rest Assured

Avec les requêtes POST et PUT, nous envoyons des données au serveur et sa création de ressources / mise à jour des ressources, vous pouvez considérer cela comme une opération d'écriture ou de mise à jour.

Les données qui sont envoyées au serveur dans une requête POST sont envoyées dans le corps de la requête HTTP / appel API. 

Le type de contenu ou de données qui est envoyé peut être de format différent selon l'API, c'est-à-dire que XML, JSON ou un autre format est défini par l'en-tête Content-Type. 

Si le corps POST est constitué de données JSON, l'en-tête Content-Type sera application/json. De même, pour une requête POST constituée d'un XML, l'en-tête Content-Type sera de type application/xml.

Voici l'extrait de code ci-dessous pour le même:

donné (). contentType ("application / json"). param ("pk", "pv"). when (). body ("JsonPAyloadString"). post ("url"). then (). assertThat (). statusCode (200);

REMARQUE: Il existe différentes façons de transmettre le corps de la charge utile / de la requête à l'intérieur de la méthode «body» comme String (comme indiqué dans l'extrait de code ci-dessus), JsonObject, sous forme de fichier, etc.

Demande PUT avec Rest Assured:

donné (). contentType ("application / json"). param ("pk", "pv"). when (). body ("JsonPAyloadString"). put ("url"). then (). assertThat (). statusCode (200);

Supprimer la demande avec Rest-Assured:

donné (). contentType ("application / json"). param ("pk", "pv"). when (). delete ("url"). then (). assertThat (). statusCode (200);

Et de cette façon, nous pouvons créer différents appels d'API Rest pour différents verbes d'API (GET / POST / PUT / DELETE, etc.)

Sérialisation et désérialisation en Java:

La sérialisation est essentiellement un traitement ou une conversion de l'état de l'objet en un flux d'octets. D'autre part, la désérialisation en Java traite ou convertit le flux d'octets en objet Java réel dans la mémoire. Ce mécanisme est utilisé dans la persistance d'Object.

Ci-dessous est le schéma de principe pour le même 

1ESLuGPTk5gUs9eA5 OXkbw KyHeRnO9TdX bg OEo3 ZD7BJ9HqLY HcOaf9saeK137JSzmDj7 TY2WmrlVogzLzkgmN1gvLvyaF6cdGb6psTcv0HVH98J45L4b1a0c3ucUvJ6p

Avantages de la sérialisation

A. Pour enregistrer / conserver l'état d'un objet.

B. Pour faire circuler un objet sur un réseau.

Réalisation de la sérialisation avec JAVA

Pour obtenir un objet Java sérialisable, nous devons implémenter l'interface java.io.Serializable.

La classe ObjectOutputStream qui contient la méthode writeObject () responsable de la sérialisation d'un Object.

La classe ObjectInputStream contient également une autre méthode appelée readObject () qui est responsable de la désérialisation d'un objet.

classes qui implémentent l'interface java.io.Serializable, leur objet ne peut être sérialisé.

Serializable est juste une interface de marqueur et comme toute autre interface du marché, il n'a pas de membre de données ou de méthode qui lui est associé.qui est utilisé pour «marquer» les classes Java afin que les objets de ces classes obtiennent certaines capacités. Comme quelques autres interfaces de marqueur sont: - Clonable et à distance, etc.

Remarques :

1. Si une classe parente a implémenté une interface Serializable, alors la classe enfant n'est pas obligée de l'implémenter mais l'inverse n'est pas applicable.

2. Seuls les membres de données non statiques sont stockés avec le processus de sérialisation.

3. Les membres de données statiques et les membres de données transitoires ne sont pas stockés par la sérialisation. Ainsi, au cas où nous n'aurions pas besoin de stocker la valeur du membre de données non statique, nous pouvons la rendre transitoire.

4. Le constructeur n'est jamais appelé lorsqu'un objet est désérialisé.

ÉTAPE 1: La première étape est essentiellement la création d'une classe qui implémente l'interface Serializable:

importer java.io.Serializable ;
public class Dummy implémente Serializable {
    int privé i;
    données de chaîne privées;
    public Dummy (int i, données de chaîne)
    {
        ceci.i = je;
        this.data = données;
    }
}

ÉTAPE 2: Créez une classe pour la sérialiser:

importer java.io.FileNotFoundException ;
importer java.io.FileOutputStream ;
import java.io.IOException;
importer java.io.ObjectOutputStream ;
public class Serialize {
    public static void Serialization (Object classObject, String fileName) {
        essayez {
            FileOutputStream fileStream = new FileOutputStream (fileName);
            ObjectOutputStream objectStream = new ObjectOutputStream (fileStream);
            objectStream.writeObject (classObject);
            objectStream.close ();
            fileStream.close ();
        } catch (FileNotFoundException e) {
            // TODO Bloc catch généré automatiquement
            e.printStackTrace ();
        } capture (IOException e) {
            // TODO Bloc catch généré automatiquement
            e.printStackTrace ();
        }
    }
    public void main (String [] args) {
        Dummy dummyObj = nouveau Dummy (10, "Lambda-geeks");
        Sérialisation (dummyObj, "DummSerialized");
    }
}

ÉTAPE 3: Une fois l'étape 2 terminée avec succès, vous pourrez voir un fichier créé avec des données, ces données sont essentiellement des données sérialisées des membres de l'objet.

  Désérialisation avec java:

Voici l'extrait de code ci-dessous:

 Public static Object DeSerialize (String fileName)
    {
        essayez {
            FileInputStream fileStream = new FileInputStream (new File (fileName));
            ObjectInputStream objectStream = new ObjectInputStream (fileStream);
            Object deserializeObject = objectStream.readObject ();
            objectStream.close ();
            fileStream.close ();
            retourne deserializeObject ;
        } catch (FileNotFoundException e) {
            e.printStackTrace ();
        } capture (IOException e) {
            e.printStackTrace ();
        } catch (ClassNotFoundException e) {
            e.printStackTrace ();
        }
        renvoie null ;
    }

Le code du conducteur va comme ceci:

 public void main (String [] args) {
      / * Dummy dummyObj = nouveau Dummy (10, "Lambda-geeks");
        Sérialisation (dummyObj, "DummSerialized");
        System.out.println ("------------------------------------------- ------------------------------- ");
      */
        Dummy deSerializedRect = (Dummy) DeSerialize ("DummSerialized");
        System.out.println ("Données d'un objet sérialisé" + deSerializedRect.print ());
        System.out.println ("------------------------------------------- ------------------------------- ");
    }

JSONPATH Plus Syntaxe / Requête:

Supposons un JSON comme ci-dessous:

{
  "OrganizationDetails": "Détails factices de l'organisation",
  "Région": "Asie",
  "Détails Emp": [
    {
      "Org": "lambda-Geeks",
      "Information": {
        "Ph": 1234567890,
        "Ajouter": "XYZ",
        "Âge": 45
      }
    },
    {
      "Org": "lambda-Geeks-2",
      "Information": {
        "Ph": 2134561230,
        "Ajouter": "ABC",
        "Âge": 35
      }
    }
  ]
}

dans le JSON ci-dessus, OrganizationDetails & Region sont appelés en tant que nœud Leaf, car ils n'ont pas d'autres nœuds / éléments enfants, mais comme d'un autre côté les Emp-Details ayant un nœud enfant, d'où ce nœud n'est pas appelé Leaf.

Ici, si nous essayons d'obtenir la valeur de OrganizationDetails, nous devons utiliser:

$ .OrganizationDétails 
Cela se traduira par:
 [
  "Détails factices de l'organisation"
]

Comme Wise pour obtenir les données de la région, nous devons écrire:

$ .Région 

Si nous voulons trouver la valeur de l'âge pour le premier employé, nous pourrions écrire:

$ .Emp-Details [0] .Information.Age
Cela se traduira par:
[
  45
]

Pour l'âge du 2e employé, nous pourrions écrire comme

$ .Emp-Details [1] .Information.Age
Cela se traduira par: [35]

De cette façon, nous pouvons comprendre l'expression / requête JsonPath pour récupérer les données pour les champs respectifs dans le JSON.