Un guide de REST-assuré

Haut Jackson

Je viens d'annoncer le nouveau cours Learn Spring , axé sur les principes de base de Spring 5 et Spring Boot 2:

>> VOIR LE COURS

1. Introduction

REST-assuré a été conçu pour simplifier les tests et la validation des API REST et est fortement influencé par les techniques de test utilisées dans les langages dynamiques tels que Ruby et Groovy.

La bibliothèque a un support solide pour HTTP, en commençant bien sûr par les verbes et les opérations HTTP standard, mais allant également bien au-delà de ces bases.

Dans ce guide, nous allons explorer REST-assuré et nous allons utiliser Hamcrest pour faire des assertions. Si vous n'êtes pas déjà familiarisé avec Hamcrest, vous devez d'abord réviser le tutoriel: Tester avec Hamcrest.

Aussi, pour en savoir plus sur les cas d'utilisation plus avancés de REST-Assuré, consultez nos autres articles:

  • REST assuré avec Groovy
  • Validation de schéma JSON avec garantie REST
  • Paramètres, en-têtes et cookies avec assurance REST

Passons maintenant à un exemple simple.

2. Exemple de test simple

Avant de commencer, assurons-nous que nos tests ont les importations statiques suivantes:

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

Nous en aurons besoin pour simplifier les tests et accéder facilement aux principales API.

Maintenant, commençons par l'exemple simple - un système de paris de base exposant certaines données pour les jeux:

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

Disons qu'il s'agit de la réponse JSON provenant de la frappe de l'API déployée localement - // localhost: 8080 / events? Id = 390. :

Utilisons maintenant REST-assuré pour vérifier certaines fonctionnalités intéressantes de la réponse JSON:

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

Donc, ce que nous avons fait ici est - nous avons vérifié qu'un appel au point final / événements? Id = 390 répond avec un corps contenant une chaîne JSON dont le leagueId de l' objet de données est 35.

Jetons un coup d'œil à un exemple plus intéressant. Supposons que vous souhaitiez vérifier que le tableau des cotes contient des enregistrements avec des prix de 1,30 et 5,25 :

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

3. Configuration assurée par REST

Si votre outil de dépendance préféré est Maven, nous ajoutons la dépendance suivante dans le fichier pom.xml :

 io.rest-assured rest-assured 3.3.0 test 

Pour obtenir la dernière version, suivez ce lien.

REST-assuré tire parti de la puissance des correspondants Hamcrest pour exécuter ses assertions, nous devons donc également inclure cette dépendance:

 org.hamcrest hamcrest-all 2.1 

La dernière version sera toujours disponible sur ce lien.

4. Validation de la racine JSON anonyme

Considérez un tableau qui comprend des primitives plutôt que des objets:

[1, 2, 3]

Cela s'appelle une racine JSON anonyme, ce qui signifie qu'elle n'a pas de paire clé-valeur mais qu'il s'agit toujours de données JSON valides.

Nous pouvons exécuter la validation dans un tel scénario en utilisant le $symbole ou une chaîne vide («») comme chemin. Supposons que nous exposions le service ci-dessus via // localhost: 8080 / json, puis nous pouvons le valider comme ceci avec REST-assuré:

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

ou comme ça:

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

5. Flotteurs et doubles

Lorsque nous commençons à utiliser REST-Assuré pour tester nos services REST, nous devons comprendre que les nombres à virgule flottante dans les réponses JSON sont mappés au flottant de type primitif .

L'utilisation du type float n'est pas interchangeable avec double comme c'est le cas pour de nombreux scénarios en java.

Voici un exemple concret de cette réponse:

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

Supposons que nous exécutons le test suivant sur la valeur de ck :

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

Ce test échouera même si la valeur que nous testons est égale à la valeur de la réponse. C'est parce que nous comparons à un double plutôt qu'à un flottant .

To make it work, we have to explicitly specify the operand to the equalTo matcher method as a float, like so:

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

6. Specifying the Request Method

Typically, we would perform a request by calling a method such as get(), corresponding to the request method we want to use.

In addition, we can also specify the HTTP verb using the request() method:

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

The example above is equivalent to using get() directly.

Similarly, we can send HEAD, CONNECT and OPTIONS requests:

@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); }

Dans cet exemple, nous voulons valider que le code d'état est 200. Ce n'est qu'en cas d'échec que la demande et la réponse seront enregistrées.

12. Conclusion

Dans ce didacticiel, nous avons exploré le cadre assuré par REST et examiné ses fonctionnalités les plus importantes que nous pouvons utiliser pour tester nos services RESTful et valider leurs réponses.

La mise en œuvre complète de tous ces exemples et extraits de code se trouve dans le projet GitHub assuré par REST.

Jackson bas

Je viens d'annoncer le nouveau cours Learn Spring , axé sur les principes de base de Spring 5 et Spring Boot 2:

>> VOIR LE COURS