Guida importante per il test e il RestAssured dell'API Rest

In questo esaustivo tutorial Rest Assured impareremo il Rest API Testing in profondità, API Test Automation insieme a Rest Assured in un approccio modulare

Cos'è RestAssured e il suo utilizzo

Rest Assured è una tecnologia open source molto utilizzata per i test di automazione delle API REST, basata su una libreria basata su Java.

Rest Assured interagisce con Rest API in una modalità client headless, possiamo migliorare la stessa richiesta aggiungendo diversi livelli per formare la richiesta e creare una richiesta HTTP tramite diversi verbi HTTPS al server.

La libreria integrata Rest Assured fornisce enormi metodi e utilità per eseguire la convalida della risposta ricevuta dal server, come il messaggio di stato, il codice di stato e il corpo della risposta.

Questa serie completa di tutorial Rest Assured per il test dell'automazione dell'API REST è costituita dai seguenti argomenti:

RestAssured -Il resto assicurato tutorial api test
Automazione API sicura

Per iniziare: configurazione di restAssured con lo strumento Build, ovvero Maven / gradle

PASSO 1: Se stai lavorando con Maven, aggiungi la seguente dipendenza in pom.xml (puoi scegliere anche qualsiasi altra versione):

Per iniziare con REST Assured, aggiungi semplicemente la dipendenza al tuo progetto. 


    io. rest-assicurato
    stia tranquillo
    4.3.0
    test

Se stai lavorando con gradle, aggiungi quanto segue in build.gradle (di nuovo puoi scegliere anche qualsiasi altra versione):

testCompile gruppo: "io.rest-assured", nome: "rest-assured", versione: "4.3.0"

FASE 2: REST Assured può essere integrato e utilizzato molto facilmente con i framework di unit test esistenti, ad esempio Testng, JUnit

Qui stiamo usando testNg come per lo Unit Test Framework è interessato.

Una volta importate le librerie di Rest Assured, è necessario aggiungere le seguenti importazioni statiche alle nostre classi di test:

import statico io.restassured.RestAssured. *;

import statico org.hamcrest.Matchers. *;

NOTA: Per questo scopo di apprendimento imminente, testeremo l'API per sviluppatori Ergast, che può essere trovato qui. Questa API fornisce dati storici relativi a gare di Formula 1, piloti, circuiti, ecc.

Familiarità con la sintassi:

Rest Assured supporta il formato BDD (Sintassi del cetriolino(Sintassi del cetriolino) e come funziona ed è molto semplice.

T-01: Il nostro primo script che sostanzialmente convalida il numero di circuiti in F1 nel 1 utilizzando questa API (http://ergast.com/api/f1/2017/circuits.json)

@Test (description = "Number Of Circuits in 2017 Season Should Be 20") public void validatingNumberOfCircuits () {given (). When (). Get ("http://ergast.com/api/f1/2017/circuits. json "). then (). assertThat (). body ("MRData.CircuitTable.Circuits.circuitId", hasSize (20)); }

Convalida della risposta dell'API Rest :

1. Acquisisce la risposta JSON della richiesta API.

2. Query per circuitId utilizzando l'espressione GPath "MRData.CircuitTable.Circuits.circuitId"

3. Verifica che la raccolta di elementi circuitId abbia la dimensione di 20

Qui stiamo usando Matchers Hamcrest per varie convalide come

Esistono vari altri metodi utili per eseguire determinate convalide.

È inoltre possibile fare riferimento alla documentazione della libreria Hamcrest per un elenco completo di abbinamenti e metodi.

Convalida del codice di risposta:

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

Convalida del tipo di contenuto

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

Convalida dell'intestazione "Content-Length"

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

Convalida multipla in un singolo test come (utilizzando i metodi e ()):

@Test (description = "Il numero di circuiti nella stagione 2017 dovrebbe essere 20")
    public void validatingNumberOfCircuits () {
        given (). when (). get ("http://ergast.com/api/f1/2017/circuits.json") .then (). assertThat (). header ("Content-Length", equalTo (" 4551 ")). E (). StatusCode (200);
    }

Convalida dell'elemento / attributo del corpo della risposta:

Possiamo usare JsonPath per recuperare il valore degli attributi json e inserire l'asserzione usando TestNg

@Test (description = "Validation of series Name which is f1")
    public void validatingSeriesName () {
        // Converte ResponseBody in String
        String responseBody = given (). When (). Get ("http://ergast.com/api/f1/2017/circuits.json") .getBody (). AsString ();
        // Crea oggetto JsonPath passando il corpo della risposta come stringa
        JsonPath resJson = nuovo JsonPath (responseBody);
        // Recupera la serie di valori dell'attributo in MRData
        String seriesName = resJson.getString ("MRData.series");
        // Asserzione TestNg utente
        Assert.assertEquals ("f1", seriesName);
    }

Allo stesso modo potremmo ottenere il valore della risposta XML usando XMLPath. Qui stiamo lavorando con JSON, quindi abbiamo usato qui JSonPath

Le API RESTful supportano solo due tipi di parametri:

A. Parametri della query: Qui i parametri vengono aggiunti alla fine dell'endpoint API e potrebbero essere identificati dal punto interrogativo e formano una coppia di valori chiave come 

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

Qui nell'API sopra "q" è il parametro e "https://www.wikipedia.org/" è il valore di quel parametro, se dobbiamo cercare "QUALCOSA_ELSE_TEXT'potremmo sostituire il valore del parametro 'q' con 'QUALCOSA_ELSE_TEXT'al posto di https://www.wikipedia.org/.

B. Parametri del percorso: Questi sono la parte dell'endpoint API RESTful. 

per esempio. endpoint che abbiamo utilizzato in precedenza: http://ergast.com/api/f1/2017/circuits.json, qui "2017" è un valore del parametro del percorso.

Per ottenere un risultato per l'anno 2016 potremmo sostituire il 2017 con il 2016 quindi l'API fornirà il corpo di risposta per il 2016.

Test utilizzando Path Params per RestAssured

@Test (description = "Validation of number of Circuits using Path Params")
    public void testWithPathParams () {
        String seasonNumber = "2017";
       String responseBody = given (). PathParam ("season", seasonNumber) .when (). Get ("http://ergast.com/api/f1/{season}/circuits.json") .getBody (). AsString ();
        // Crea oggetto JsonPath passando il corpo della risposta come stringa
        JsonPath resJson = nuovo JsonPath (responseBody);
        // Recupera la serie di valori dell'attributo in MRData
        String seriesName = resJson.getString ("MRData.series");
        // Asserzione TestNg utente
        Assert.assertEquals ("f1", seriesName);
    }

Test utilizzando Query Params per RestAssured

@Test (description = "Validation of Google search using Query Params")
    public void testWithPathParams () {
        String searchItem = "https://www.wikipedia.org/";
  given (). queryParam ("q", searchItem) .when (). get ("https://www.google.com/search") .then (). assertThat (). statusCode (200);
    }

Parametrizzazione dei test:

Possiamo eseguire test basati sui dati (ovvero lo stesso script di test verrà eseguito più volte con diversi set di dati di input e fornirà diversi dati di output) utilizzando Rest Assured 

PASSAGGIO 1: creazione di un provider di dati testNg.

PASSAGGIO 2: utilizzare il provider di dati nello script di test.

@DataProvider (name = "seasonsAndRaceNumbers")
    public Object [] [] testDataFeed () {
        restituisci nuovo oggetto [] [] {
                {"2017", 20},
                {"2016", 21}
        };
    }
@Test (description = "Number Of Circuits validation in different Seasons", dataProvider = "stagioniAndRaceNumbers") public void circuitNumberValidation (String seasonYear, int raceNumbers) {given ().pathParam ("season", seasonYear) .when (). get ("http://ergast.com/api/f1/{stagione}/circuits.json "). quindi (). assertThat (). body (" MRData.CircuitTable.Circuits.circuitId ", hasSize (numeri di gara)); }

Utilizzo di parametri multivalore con RestAssured 

I parametri multivalore sono quei parametri che hanno più di un valore per nome parametro (cioè un elenco di valori per paramKey), possiamo affrontarli come di seguito:

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

Oppure potremmo preparare una lista e passare la lista come valore di paramKey come:

Elenco paramValue = new new ArrayList ();
paramValue.add ("paramvalue1");
paramValue.add (“paramvalue2);
given (). param ("paramKey", paramValue) .when (). get ("API URL");
Lavorare con i cookie con RestAssured 
given (). cookie ("cookieK", "cookieVal"). when (). get ("API URL");

Or 

Possiamo anche specificare un cookie multivalore qui come:

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

Lavorare con le intestazioni:

Possiamo specificare in una richiesta usando header / header come:

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

Lavorare con il tipo di contenuto:

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

Or 

given (). contentType (ContentType.JSON) .when (). get ();

Misura il tempo di risposta:

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

Autenticazione API Rest

REST assicurato supporta diversi schemi di autenticazione, ad esempio OAuth, digest, certificate, form e preemptive basic authentication. Possiamo impostare l'autenticazione per ogni richiesta 

ecco una richiesta di esempio che utilizza lo stesso:

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

D'altra parte l'autenticazione e definita nell'approccio seguente per le richieste HTTP:

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

Tipi di AUTH di base:

Esistono due tipi di autenticazione di base, "preventiva" e "autenticazione di base con token contestato".

Autenticazione di base preventiva:

Ciò invierà le credenziali di autenticazione di base anche prima che il server fornisca una risposta non autorizzata in determinate situazioni insieme all'attivazione della richiesta, riducendo così il sovraccarico di effettuare una connessione aggiuntiva. In genere si tratta di situazioni che si verificano principalmente a meno che non stiamo testando la capacità dei server di sfidare. 

Eg.

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

Autenticazione di base sfidata

D'altra parte, "autenticazione di base contestata" REST Assured non fornirà le credenziali a meno che il server non le abbia esplicitamente richieste, ad esempio il server lancia la risposta non autorizzata. Dopo quella risposta non autorizzata Rest-Assured invia un'altra richiesta al server che è l'autenticazione.

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

Autenticazione digest

Al momento è stata presa in considerazione solo l '"autenticazione del digest con contestazione". per esempio:

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

Autenticazione del modulo

Potremmo raggiungere questo obiettivo principalmente in 3 diversi approcci a seconda dell'applicazione / degli scenari:

L'autenticazione tramite modulo è molto popolare su Internet e prevede che un utente inserisca le proprie credenziali, ad esempio nome utente e password, attraverso una pagina Web e acceda al sistema. Questo problema potrebbe essere risolto utilizzando questo 

given (). auth (). form ("uName", "pWd").
quando (). get ("URL");
quindi (). statusCode (200);

Anche se questo potrebbe non funzionare in quanto è ottimale e potrebbe passare o fallire a seconda della complessità della pagina web. Un'opzione migliore è fornire questi dettagli quando si configura l'autenticazione del modulo nell'approccio seguente:

given (). auth (). form ("uName", "pwd", new FormAuthConfig ("/ 'menziona qui il nome dell'azione del modulo che fa parte del codice della pagina html nel tag form'", "uName", "pwd ")). when (). get (" URL "). then (). statusCode (200);

In questo approccio, REST Assured internamente non richiederà di attivare ulteriori richieste e di analizzare la pagina web. 

Se nel caso in cui stai utilizzando l'impostazione predefinita Spring Security, allora viene attivato un FormAuthConfig predefinito.

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

NOTA: Se vogliamo inviare dati di input aggiuntivi insieme all'autenticazione del modulo, potremmo scrivere quanto segue:

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

CSRF:

CSRF sta per Cross-site request forgery.

Al giorno d'oggi è molto comune per il server fornire un token CSRF con la risposta per evitare gli attacchi alla sicurezza CSRF. REST Assured lo supporta utilizzando un parser automatico e fornendo il token CSRF. 

Per ottenere questo REST Assicurato è necessario fare un'ulteriore richiesta e analizzare (poche posizioni) del sito web.

Possiamo abilitare il supporto CSRF scrivendo il codice seguente:

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

Oltre ad assistere REST Assured e rendere l'analisi più impeccabile e robusta, possiamo fornire il nome del campo CSRF (qui assumiamo che stiamo utilizzando i valori predefiniti di Spring Security e potremmo usare springSecurity FormAuthConfig predefinito):

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

Per impostazione predefinita, il valore CSRF viene passato come parametro del modulo con la richiesta, ma possiamo configurarlo per inviarlo come intestazione se nel caso è richiesto come di seguito:

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

OAuth 1:

OAuth 1 richiede che Scribe sia nel classpath. Per utilizzare l'autenticazione oAuth 1 possiamo fare:

dato (). auth (). oauth (..). when (). ..

OAuth 2:

dato (). auth (). oauth2 (accessToken) .when (). ..

Nell'approccio precedente, il token di accesso OAuth2 verrà considerato in un'intestazione. Per essere più espliciti possiamo anche fare:

dato (). auth (). preemptive (). oauth2 (accessToken) .when (). ..

Passaggio di file, array di byte, flusso di input o testo nella richiesta:

Quando si inviano grandi quantità di dati al server, è generalmente un approccio comune utilizzare la tecnica dei dati del modulo multipart. Siate certi di fornire metodi chiamati multiPart che ci consentono di specificare un file, un array di byte, un flusso di input o un testo da caricare. 

given (). multiPart (new File ("/ File_Path")). when (). post ("/ upload");

Creazione di richieste POST con tranquillità

Con le richieste POST e PUT, inviamo i dati al server e la sua fondamentalmente creazione di risorse / aggiornamento delle risorse, puoi considerarla come un'operazione di scrittura o aggiornamento.

I dati che vengono inviati al server in una richiesta POST vengono inviati nel corpo della richiesta HTTP / chiamata API. 

Il tipo di contenuto o di dati che viene inviato può essere di formato diverso a seconda dell'API, ovvero XML, JSON o un altro formato è definito dall'intestazione Content-Type. 

Se il corpo del POST è costituito da dati JSON, l'intestazione Content-Type sarà application/json. Allo stesso modo, per una richiesta POST costituita da un XML, l'intestazione Content-Type sarebbe di tipo application/xml.

Ecco lo snippet di codice seguente per lo stesso:

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

NOTA: Ci sono diversi modi in cui possiamo passare il corpo del payload / richiesta all'interno del metodo "body" come String (come mostrato nello snippet sopra), JsonObject, come File, ecc.

Richiedi PUT con tranquillità:

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

Elimina richiesta con Rest-Assured:

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

In questo modo possiamo creare diverse chiamate API Rest per diversi verbi API (GET / POST / PUT / DELETE ecc.)

Serializzazione e deserializzazione in Java:

La serializzazione è fondamentalmente l'elaborazione o la conversione dello stato dell'oggetto in un flusso di byte. D'altra parte, la deserializzazione in Java sta elaborando o convertendo il flusso di byte in un oggetto Java effettivo all'interno della memoria. Questo meccanismo viene utilizzato nella persistenza di Object.

Di seguito è riportato lo schema a blocchi per lo stesso 

1ESLuGPTk5gUs9eA5 OXkbw KyHeRnO9TdX bg OEo3 ZD7BJ9HqLY HcOaf9saeK137JSzmDj7 TY2WmrlVogzLzkgmN1gvLvyaF6cdGb6psTcv0HVH98J45L4b1a0c3ucUvJ6p

Vantaggi della serializzazione

A. Per salvare / mantenere lo stato di un oggetto.

B. Far fluire un oggetto attraverso una rete.

Ottenere la serializzazione con JAVA

Per ottenere un oggetto Java serializzabile è necessario implementare l'interfaccia java.io.Serializable.

La classe ObjectOutputStream che contiene il metodo writeObject () responsabile della serializzazione di un oggetto.

La classe ObjectInputStream contiene anche un altro metodo chiamato readObject () che è responsabile della deserializzazione di un oggetto.

classi che implementano l'interfaccia java.io.Serializable, il loro oggetto può essere solo serializzato.

Serializable è solo un'interfaccia marker e, come altre interfacce di mercato, non ha alcun membro dati o metodo ad essa associato. Che viene utilizzato per "contrassegnare" le classi java in modo che gli oggetti di queste classi ottengano determinate funzionalità. Come poche altre interfacce marker sono: - Clonabile e Remota ecc.

Appunti :

1. Se una classe genitore ha implementato un'interfaccia serializzabile, la classe figlia non è richiesta per implementare la stessa ma viceversa non è applicabile.

2. Solo i membri dati non statici vengono archiviati con il processo di serializzazione.

3. I membri dei dati statici e anche i membri dei dati temporanei non vengono memorizzati dalla serializzazione. Quindi, nel caso in cui non abbiamo bisogno di memorizzare il valore del membro dei dati non statici, possiamo renderlo transitorio.

4. Il costruttore non viene mai chiamato quando un oggetto viene deserializzato.

PASSO 1: Il primo passo è fondamentalmente la creazione di una classe che implementa l'interfaccia Serializable:

import java.io.Serializzabile;
public class Dummy implementa Serializable {
    int i privato;
    dati String privati;
    public Dummy (int i, String data)
    {
        questo.i = io;
        this.data = data;
    }
}

PASSAGGIO 2: creare una classe per serializzarla:

import java.io.FileNotFoundException;
importa java.io.FileOutputStream;
import java.io.IOException;
importare java.io.ObjectOutputStream;
public class Serialize {
    public static void Serialization (Object classObject, String fileName) {
        provare {
            FileOutputStream fileStream = nuovo FileOutputStream (fileName);
            ObjectOutputStream objectStream = nuovo ObjectOutputStream (fileStream);
            objectStream.writeObject (classObject);
            objectStream.close ();
            fileStream.close ();
        } cattura (FileNotFoundException e) {
            // TODO Blocco catch generato automaticamente
            e.printStackTrace ();
        } cattura (IOException e) {
            // TODO Blocco catch generato automaticamente
            e.printStackTrace ();
        }
    }
    Main (string [] args) {public static void
        Dummy dummyObj = new Dummy (10, "Lambda-geek");
        Serializzazione (dummyObj, "DummSerialized");
    }
}

PASSO 3: Una volta completato con successo lo Step2, vedrai un file creato con alcuni dati al suo interno, che sono fondamentalmente dati serializzati dei membri dell'Oggetto.

  Deserializzazione con java:

Di seguito è riportato lo snippet di codice:

 public static Object DeSerialize (String fileName)
    {
        provare {
            FileInputStream fileStream = nuovo FileInputStream (nuovo File (fileName));
            ObjectInputStream objectStream = nuovo ObjectInputStream (fileStream);
            Object deserializeObject = objectStream.readObject ();
            objectStream.close ();
            fileStream.close ();
            return deserializzazioneOggetto;
        } cattura (FileNotFoundException e) {
            e.printStackTrace ();
        } cattura (IOException e) {
            e.printStackTrace ();
        } cattura (ClassNotFoundException e) {
            e.printStackTrace ();
        }
        restituisce null;
    }

Il codice del driver funziona così:

 Main (string [] args) {public static void
      / * Dummy dummyObj = new Dummy (10, "Lambda-geek");
        Serializzazione (dummyObj, "DummSerialized");
        System.out.println ("------------------------------------------- ------------------------------- ");
      */
        Dummy deSerializedRect = (Dummy) DeSerialize ("DummSerialized");
        System.out.println ("Dati da oggetto serializzato" + deSerializedRect.print ());
        System.out.println ("------------------------------------------- ------------------------------- ");
    }

JSONPATH Più sintassi / query:

Assumiamo un JSON come di seguito:

{
  "OrganizationDetails": "Dettagli fittizi dell'organizzazione",
  "Regione": "Asia",
  "Emp-Details": [
    {
      "Org": "lambda-Geeks",
      "Informazione": {
        "Ph": 1234567890,
        "Aggiungi": "XYZ",
        "Età": 45
      }
    },
    {
      "Org": "lambda-Geeks-2",
      "Informazione": {
        "Ph": 2134561230,
        "Aggiungi": "ABC",
        "Età": 35
      }
    }
  ]
}

nel JSON di cui sopra, OrganizationDetails & Region sono chiamati come nodo Foglia perché non hanno ulteriori nodi / elementi figlio ma come d'altro canto gli Emp-Details hanno nodo figlio, quindi non è indicato come nodo Foglia.

Qui, se proviamo a ottenere il valore di OrganizationDetails, dobbiamo usare:

$ .OrganizationDetails 
Ciò si tradurrà in:
 [
  "Dettagli fittizi dell'organizzazione"
]

Come Wise, per ottenere i dati per la regione dobbiamo scrivere:

$ .Region 

Se vogliamo trovare il valore di Età per il primo dipendente, potremmo scrivere:

$ .Emp-Details [0] .Information.Age
Ciò si tradurrà in:
[
  45
]

Per l'Età del 2 ° Impiegato potremmo scrivere come

$ .Emp-Details [1] .Information.Age
Ciò si tradurrà in: [35]

In questo modo possiamo capire l'espressione / query JsonPath per recuperare i dati per i rispettivi campi nel JSON.