Una guida al riposo assicurato

Jackson Top

Ho appena annunciato il nuovo corso Learn Spring , incentrato sui fondamenti di Spring 5 e Spring Boot 2:

>> SCOPRI IL CORSO

1. Introduzione

REST-assicurato è stato progettato per semplificare il test e la convalida delle API REST ed è fortemente influenzato dalle tecniche di test utilizzate in linguaggi dinamici come Ruby e Groovy.

La libreria ha un solido supporto per HTTP, a partire ovviamente dai verbi e dalle operazioni HTTP standard, ma va anche ben oltre queste basi.

In questa guida, esploreremo REST-assicurato e useremo Hamcrest per fare asserzioni. Se non hai già familiarità con Hamcrest, dovresti prima rispolverare il tutorial: Testing with Hamcrest.

Inoltre, per conoscere i casi d'uso più avanzati di REST-assicurato, consulta i nostri altri articoli:

  • RIPOSO assicurato con Groovy
  • Convalida dello schema JSON con garanzia REST
  • Parametri, intestazioni e cookie con garanzia REST

Ora tuffiamoci con un semplice esempio.

2. Test di esempio semplice

Prima di iniziare, assicuriamoci che i nostri test abbiano le seguenti importazioni statiche:

io.restassured.RestAssured.* io.restassured.matcher.RestAssuredMatchers.* org.hamcrest.Matchers.*

Ne avremo bisogno per mantenere i test semplici e avere un facile accesso alle API principali.

Ora, iniziamo con il semplice esempio: un sistema di scommesse di base che espone alcuni dati per i giochi:

{ "id": "390", "data": { "leagueId": 35, "homeTeam": "Norway", "visitingTeam": "England", }, "odds": [{ "price": "1.30", "name": "1" }, { "price": "5.25", "name": "X" }] }

Supponiamo che questa sia la risposta JSON dal colpire l'API distribuita localmente - // localhost: 8080 / events? Id = 390. :

Usiamo ora REST-assicurato per verificare alcune caratteristiche interessanti del JSON di risposta:

@Test public void givenUrl_whenSuccessOnGetsResponseAndJsonHasRequiredKV_thenCorrect() { get("/events?id=390").then().statusCode(200).assertThat() .body("data.leagueId", equalTo(35)); }

Quindi, quello che abbiamo fatto qui è - abbiamo verificato che una chiamata agli endpoint / eventi id = 390? Risponde con un corpo che contiene una stringa JSON cui leagueId dei dati dell'oggetto è di 35.

Diamo un'occhiata a un esempio più interessante. Supponiamo che desideri verificare che l' array di quote abbia record con prezzi 1.30 e 5.25 :

@Test public void givenUrl_whenJsonResponseHasArrayWithGivenValuesUnderKey_thenCorrect() { get("/events?id=390").then().assertThat() .body("odds.price", hasItems("1.30", "5.25")); }

3. Configurazione assicurata da REST

Se il tuo strumento di dipendenza preferito è Maven, aggiungiamo la seguente dipendenza nel file pom.xml :

 io.rest-assured rest-assured 3.3.0 test 

Per ottenere l'ultima versione, segui questo link.

REST-assicurato sfrutta la potenza dei matcher di Hamcrest per eseguire le sue affermazioni, quindi dobbiamo includere anche quella dipendenza:

 org.hamcrest hamcrest-all 2.1 

L'ultima versione sarà sempre disponibile a questo link.

4. Convalida radice JSON anonima

Considera un array che comprende primitive piuttosto che oggetti:

[1, 2, 3]

Questa è chiamata radice JSON anonima, il che significa che non ha una coppia chiave-valore, tuttavia sono ancora dati JSON validi.

È possibile eseguire la convalida in tale scenario utilizzando il $simbolo o una stringa vuota ("") come percorso. Supponiamo di esporre il servizio precedente tramite // localhost: 8080 / json, quindi possiamo convalidarlo in questo modo con REST-assicurato:

when().get("/json").then().body("$", hasItems(1, 2, 3));

o così:

when().get("/json").then().body("", hasItems(1, 2, 3));

5. Galleggianti e doppi

Quando iniziamo a utilizzare REST-assicurato per testare i nostri servizi REST, dobbiamo capire che i numeri in virgola mobile nelle risposte JSON sono mappati al tipo float primitivo .

L'uso del tipo float non è intercambiabile con double come nel caso di molti scenari in java.

Caso in questione è questa risposta:

{ "odd": { "price": "1.30", "ck": 12.2, "name": "1" } }

supponiamo di eseguire il seguente test sul valore di ck :

get("/odd").then().assertThat().body("odd.ck", equalTo(12.2));

Questo test fallirà anche se il valore che stiamo testando è uguale al valore nella risposta. Questo perché ci stiamo confrontando con un double piuttosto che con un float .

Per farlo funzionare, dobbiamo specificare esplicitamente l'operando al metodo matcher equalTo come un float , in questo modo:

get("/odd").then().assertThat().body("odd.ck", equalTo(12.2f));

6. Specifica del metodo di richiesta

Tipicamente, eseguiremo una richiesta chiamando un metodo come get (), corrispondente al metodo di richiesta che vogliamo usare.

Inoltre, possiamo anche specificare il verbo HTTP utilizzando il metodo request () :

@Test public void whenRequestGet_thenOK(){ when().request("GET", "/users/eugenp").then().statusCode(200); }

L'esempio sopra è equivalente all'uso diretto di get () .

Allo stesso modo, possiamo inviare richieste HEAD , CONNECT e OPTIONS :

@Test public void whenRequestHead_thenOK() { when().request("HEAD", "/users/eugenp").then().statusCode(200); }

POST request also follows a similar syntax and we can specify the body by using the with() and body() methods.

Therefore, to create a new Odd by sending a POST request:

@Test public void whenRequestedPost_thenCreated() { with().body(new Odd(5.25f, 1, 13.1f, "X")) .when() .request("POST", "/odds/new") .then() .statusCode(201); }

The Odd object sent as body will automatically be converted to JSON. We can also pass any String that we want to send as our POSTbody.

7. Default Values Configuration

We can configure a lot of default values for the tests:

@Before public void setup() { RestAssured.baseURI = "//api.github.com"; RestAssured.port = 443; }

Here, we're setting a base URI and port for our requests. Besides these, we can also configure the base path, root pat, and authentication.

Note: we can also reset to the standard REST-assured defaults by using:

RestAssured.reset();

8. Measure Response Time

Let's see how we can measure the response time using the time() and timeIn() methods of the Response object:

@Test public void whenMeasureResponseTime_thenOK() { Response response = RestAssured.get("/users/eugenp"); long timeInMS = response.time(); long timeInS = response.timeIn(TimeUnit.SECONDS); assertEquals(timeInS, timeInMS/1000); }

Note that:

  • time() is used to get response time in milliseconds
  • timeIn() is used to get response time in the specified time unit

8.1. Validate Response Time

We can also validate the response time – in milliseconds – with the help of simple longMatcher:

@Test public void whenValidateResponseTime_thenSuccess() { when().get("/users/eugenp").then().time(lessThan(5000L)); }

If we want to validate the response time in a different time unit, then we'll use the time() matcher with a second TimeUnit parameter:

@Test public void whenValidateResponseTimeInSeconds_thenSuccess(){ when().get("/users/eugenp").then().time(lessThan(5L),TimeUnit.SECONDS); }

9. XML Response Verification

Not only can it validate a JSON response, itcan validate XML as well.

Let's assume we make a request to //localhost:8080/employees and we get the following response:

  Jane Daisy f  

We can verify that the first-name is Jane like so:

@Test public void givenUrl_whenXmlResponseValueTestsEqual_thenCorrect() { post("/employees").then().assertThat() .body("employees.employee.first-name", equalTo("Jane")); }

We can also verify that all values match our expected values by chaining body matchers together like so:

@Test public void givenUrl_whenMultipleXmlValuesTestEqual_thenCorrect() { post("/employees").then().assertThat() .body("employees.employee.first-name", equalTo("Jane")) .body("employees.employee.last-name", equalTo("Daisy")) .body("employees.employee.sex", equalTo("f")); }

Or using the shorthand version with variable arguments:

@Test public void givenUrl_whenMultipleXmlValuesTestEqualInShortHand_thenCorrect() { post("/employees") .then().assertThat().body("employees.employee.first-name", equalTo("Jane"),"employees.employee.last-name", equalTo("Daisy"), "employees.employee.sex", equalTo("f")); }

10. XPath for XML

We can also verify our responses using XPath. Consider the example below that executes a matcher on the first-name:

@Test public void givenUrl_whenValidatesXmlUsingXpath_thenCorrect() { post("/employees").then().assertThat(). body(hasXPath("/employees/employee/first-name", containsString("Ja"))); }

XPath also accepts an alternate way of running the equalTo matcher:

@Test public void givenUrl_whenValidatesXmlUsingXpath2_thenCorrect() { post("/employees").then().assertThat() .body(hasXPath("/employees/employee/first-name[text()='Jane']")); }

11. Logging Test Details

11.1. Log Request Details

First, let's see how to log entire request details using log().all():

@Test public void whenLogRequest_thenOK() { given().log().all() .when().get("/users/eugenp") .then().statusCode(200); }

This will log something like this:

Request method: GET Request URI: //api.github.com:443/users/eugenp Proxy:  Request params:  Query params:  Form params:  Path params:  Multiparts:  Headers: Accept=*/* Cookies:  Body: 

To log only specific parts of the request, we have the log() method in combination with params(), body(), headers(), cookies(), method(), path() eg log.().params().

Note that other libraries or filters used may alter what's actually sent to the server, so this should only be used to log the initial request specification.

11.2. Log Response Details

Similarly, we can log the response details.

In the following example we're logging the response body only:

@Test public void whenLogResponse_thenOK() { when().get("/repos/eugenp/tutorials") .then().log().body().statusCode(200); }

Sample output:

{ "id": 9754983, "name": "tutorials", "full_name": "eugenp/tutorials", "private": false, "html_url": "//github.com/eugenp/tutorials", "description": "The \"REST With Spring\" Course: ", "fork": false, "size": 72371, "license": { "key": "mit", "name": "MIT License", "spdx_id": "MIT", "url": "//api.github.com/licenses/mit" }, ... }

11.3. Log Response if Condition Occurred

We also have the option of logging the response only if an error occurred or the status code matches a given value:

@Test public void whenLogResponseIfErrorOccurred_thenSuccess() { when().get("/users/eugenp") .then().log().ifError(); when().get("/users/eugenp") .then().log().ifStatusCodeIsEqualTo(500); when().get("/users/eugenp") .then().log().ifStatusCodeMatches(greaterThan(200)); }

11.4. Log if Validation Failed

We can also log both request and response only if our validation failed:

@Test public void whenLogOnlyIfValidationFailed_thenSuccess() { when().get("/users/eugenp") .then().log().ifValidationFails().statusCode(200); given().log().ifValidationFails() .when().get("/users/eugenp") .then().statusCode(200); }

In questo esempio, vogliamo verificare che il codice di stato sia 200. Solo se fallisce, la richiesta e la risposta verranno registrate.

12. Conclusione

In questo tutorial, abbiamo esplorato il framework REST garantito e esaminato le sue caratteristiche più importanti che possiamo utilizzare per testare i nostri servizi RESTful e convalidare le loro risposte.

L'implementazione completa di tutti questi esempi e frammenti di codice può essere trovata nel progetto GitHub garantito da REST.

Jackson bottom

Ho appena annunciato il nuovo corso Learn Spring , incentrato sui fondamenti di Spring 5 e Spring Boot 2:

>> SCOPRI IL CORSO