TestAutomatisering & PerformanceTesten

De Absolute Beginners Guide voor API Testen met rest-assured.io

Omdat het moeilijk was om een eenvoudige tutorial te vinden voor rest-assured.io, ben ik na eerst zelf uit te vinden hoe het werkt, maar eens begonnen met een tutorial die de absolute basics uitlegt over rest-assured. In deze post laat ik zien hoe we op een zo eenvoudig mogelijke manier een API test kunnen maken met behulp van Java en rest-assured.io

Ik gebruik hiervoor IntelliJ IDEA 2107.1.5 Community, standaard installatie met Maven (komt mee met IntelliJ) en Java SDK 1.8 en werk onder Windows 10.

Setup

In IntelliJ starten we met een leeg Maven project met standaard instellingen.

 

In het nieuwe project zetten we de nieuwe class files in de src/test/java folder en de dependencies in de pom.xml file.

 

 

 

 

 

 

Open je pom.xml file en voeg het volgende toe in de <project> node om met rest-assured te kunnen beginnen:

<dependencies>
    <dependency>
        <groupId>io.rest-assured</groupId>
        <artifactId>rest-assured</artifactId>
        <version>3.0.6</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.testng</groupId>
        <artifactId>testng</artifactId>
        <version>6.8.8</version>
    </dependency>
    <dependency>
        <groupId>com.google.code.gson</groupId>
        <artifactId>gson</artifactId>
        <version>2.3.1</version>
    </dependency>
</dependencies>

Mooi, we zijn voorbereid en kunnen van start. Je nieuwe classes zal je voor nu willen plaatsen onder src/test/java. Voeg een nieuwe class toe onder src/test/java (rechtermuistoets, Add -> new class), dit wordt je testclass (de naam maakt niet uit je kan hem later altijd nog renamen met shift + F6).

Voor onze eerste testen gebruiken we een eenvoudige API. Later zal je dingen willen doen met authenticatie en wellicht sessies en cookies, maar laten we simpel beginnen. Een simpele API vind je bijvoorbeeld op https://jsonplaceholder.typicode.com/. Zij zijn ook de makers van de json-server waar we later kennis mee gaan maken.

Kijk maar even rond op die site. Je kan bijvoorbeeld naar de URL https://jsonplaceholder.typicode.com/posts (<- probeer maar!) gaan om alle blogposts uit de fake-blog api te halen of https://jsonplaceholder.typicode.com/posts/42 om een enkele blogpost op te halen.

Eerste Test

In onze eerste test gaan we kijken of we connectie kunnen maken met de API. Voeg de volgende methode aan je test class toe:

@Test
public void getTheFirstPost() {
    when()
            .get("https://jsonplaceholder.typicode.com/posts/1")
    .then()
            .statusCode(200);   
}

Je zal wat rode kringels krijgen omdat je de imports mist van de rest-assured libraries, laat IntelliJ dat voor je oplossen met de Alt+Enter shortcut.

Run de test en als het goed is slaagt hij.

Het is handig om de setup in je constructor opzet zodat je dit maar eenmalig hoeft te doen. In dit geval alleen de basic URL, maar je kan hier ook je authenticatie, ports etc. in kwijt. Zie de rest-assured docs voor meer.

Ik heb mijn class jsonPlaceHolderTests genoemd, dus mijn constructor heet ook zo:

public class jsonPlaceHolderTests {

    public jsonPlaceHolderTests() {
        RestAssured.baseURI = "https://jsonplaceholder.typicode.com";
    }

}

Nu hoef je voortaan niet meer de hele URL op te geven, maar alleen de api branch waar je in geinteresseerd bent, in ons geval:

@Test
public void getTheFirstPost() {
    when()
            .get("posts/1")
    .then()
            .statusCode(200)            .log().all();   
}

Vaak zal je een given() method gebruiken voor de when() methode, in dit geval is het niet nodig. Een andere verandering is dat we de respons loggen naar de console. Zo kan je zien wat er terug komt aan headers en body:

{
    "userId": 1,
    "id": 1,
    "title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit",
    "body": "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto"
}

Body Check

In de volgende test kijken we niet naar de repsons code, maar naar de inhoud. Laten we eens kijken of we een assert kunnen schrijven op de userId:

@Test
public void postShouldHaveUser() {
    when()
            .get("posts/1")
            .then()
            .body("userId", equalTo(1));
}

De equalTo is onderdeel van de HamCrest Matchers collectie, een volledige omschrijving vind je hier: http://hamcrest.org/JavaHamcrest/javadoc/1.3/org/hamcrest/Matchers.html

Zo kunnen we eenvoudig bekijken of de titel niet leeg is met de anything matcher:

@Test
public void postShouldHaveTitle() {
    when()
            .get("posts/1")
            .then()
            .body("title", anything());
}

Of als we willen kijken of alle blog-posts titel bevatten die niet leeg is:

@Test
public void allPostsShouldHaveAPopulatedTitle() {
    when()
            .get("posts")
            .then()
            .body("title", everyItem(anything()))
}

Hier krijgen we een vrij eenvoudig JSON object terug. Als je een complex object terug krijgt kan je specificeren welk gedeelte je wilt testen met de body en wat je daaruit wilt testen met de matchers. De body is het path naar het object toe zoals je dat ook zou doen met een JavaScript object. Het juiste path te pakken krijgen vergt enige oefening zoals met elke path-traversal tool.

Toevoegen en manipuleren van data

Natuurlijk willen we niet alleen informatie opvragen, maar ook toevoegen, wijzigen of verwijderen. Voordat we verder gaan met post request, zetten we eerst onze eigen JSON server op. Als je nodejs hebt geinstalleerd, heb je automatisch npm waarmee je makkelijk de json server binnen kan halen met:

npm install -g json-server

Je start de json-server met de volgende commandline. Dit neemt de default db, je kan uiteraard je eigen db maken:

json-server --watch db.json

als het goed is zal je nu zien dat je json server op port 3000 van je localhost werkt:

 

 

 

 

 

 

 

We maken een aparte class aan voor tests op deze nieuwe omgeving en een test om te kijken of we een resultaat terug kunnen krijgen:

public class jsonServerTests {
    public jsonServerTests() {
        RestAssured.baseURI = "http://localhost";
        RestAssured.port = 3000;
    }

    @Test
    public void firstPostCanBeRetrieved() {
        when()
                .get("posts/1")
                .then()
                .statusCode(200)
                .log().all();
    }
}

als het goed is moet deze test slagen.

Nu gaan we een nieuwe blog-post ‘posten’. Het posten kost iets meer werk, want we moeten een content type opgeven en de content zelf. De content geven we mee als een HashMap waarvan de values in dit geval simpele strings zijn, maar die natuurlijk ook Arrays of nieuwe HashMaps kunnen zijn.

@Test
public void newPostCanBeCreated() {
    Map<String, Object> jsonAsMap = new HashMap<String, Object>();
    jsonAsMap.put("title", "My Favorite Towel");
    jsonAsMap.put("author", "Arthur Dent");

    given()
            .contentType(JSON)
            .body(jsonAsMap)
    .when()
            .post("/posts")
            .then()
            .statusCode(201)
            .log().all();
}

Let op dat je een statuscode 201 terugkrijgt en niet 200.

Als je terugkijkt in de db.json file waar json-server in draait, zie je dit object als het goed is weer terug (dit zie je ook terug in de testlog omdat we nog steeds .log().all() gebruiken):

    {
      "author": "Arthur Dent",
      "title": "My Favorite Towel",
      "id": 2
    }

Kunnen we een item ook deleten? In onze test gaan we eerst een item aanmaken die we meteen weer verwijderen. Tijdens het aanmaken willen we de id terugkrijgen en wellicht ook de andere properties van de post. Dat kunnen we doen door in de then fase de response te extracten:

Response response =
    given()
        .contentType(JSON)
        .body(jsonAsMap)
        .when()
        .post("/posts")
        .then()
        .extract().response();

De response kunnen we als string uitlezen met behulp van asString(), maar dan moeten we met string manipulaties de Id eruit vogelen. Het zou handiger zijn als we het gelijk om konden zetten in een object en laat dat nou net mogelijk zijn.

Als eerste maken we een eenvoudige POJO:

public class SitePost {

    private int id;
    private String title;
    private String author;

    public void setAuthor(String author) {
        this.author = author;
    }
    public void setTitle(String title) {
        this.title = title;
    }
    public void setId(int id) {
        this.id = id;
    }
    public int getId() {
        return id;
    }
    public String getTitle() {
        return title;
    }
    public String getAuthor() {
        return author;
    }
}

En nu moeten we de response omzetten naar dit een SitePost object. Dat gaat verbazingwekkend eenvoudig:

SitePost sitePost = response.as(SitePost.class);

Het deleten gaat op Id en je krijgt weer een 200 als response code:

when()
    .delete("/posts/{0}", sitePost.getId())
    .then()
    .statusCode(200);

De hele test ziet er dus als volgt uit:

@Test
public void oldPostsCanBeCreatedDeleted() {
    Map<String, Object> jsonAsMap = new HashMap<String, Object>();
    jsonAsMap.put("title", "To Be Deleted");
    jsonAsMap.put("author", "Flut Schrijver");

    // setup a deletable post
    Response response =
        given()
            .contentType(JSON)
            .body(jsonAsMap)
            .when()
            .post("/posts")
            .then()
            .extract().response();

     SitePost sitePost = response.as(SitePost.class);

    //  delete it
        when()
            .delete("/posts/{0}", sitePost.getId())
        .then()
            .statusCode(200);
}

Conclusie

Hoewel er veel libraries zijn die je kan gebruiken voor rest api calls, is rest-assured.io juist specifiek gericht op testen. Het werkt via de given-when-then triple-A aanpak wat je afdwingt om je testen structureel op te pakken. Het is redelijk eenvoudig om snel een test op te zetten, als zal je bij een wat complexere configuratie ook wat meer moeten configureren met rest-assured.

Het doorlopen van de json paden is soms even puzzelen, maar in combinatie met de HamCrest matchers geeft dit een krachtige toolkit om je checks te doen. Ook hebben we in dit voorbeeld laten zien hoe je een respons om kan zetten in een Java object.

Er is nog veel meer mogelijk met deze library en daar ligt eigenlijk het heikele punt: er is niet zo heel veel documentatie beschikbaar. Dat was ook een van de redenen om juist een zo eenvoudig mogelijke tutorial hier neer te zetten. Als je deze toolkit wilt gebruiken moet je dus wel wat tijd  investeren om het volledig te doorgronden.

Dit bericht is geplaatst in Testautomatisering en getagd in API testen Java Rest rest-assured Test Automatisering

Geef een reactie

Het e-mailadres wordt niet gepubliceerd. Vereiste velden zijn gemarkeerd met *

Nieuws

Blijf op de hoogte

Testen? Begin bij de basis! | Het belang van unittesten

19/02/2018

Inleiding Mijn vrouw en ik zijn op dit moment bezig met het bouwen van een huis. In dit geval niet als bouwvakker of aannemer, maar dan toch wel als opdrachtgever. Spannend vinden we het zeker, leuk ook. Wat heeft dit te maken met unittesten zou je denken. Nou, het volgende… Het huis wordt namelijk gebouwd […]

De Absolute Beginners Guide voor API Testen met rest-assured.io

16/01/2018

Omdat het moeilijk was om een eenvoudige tutorial te vinden voor rest-assured.io, ben ik na eerst zelf uit te vinden hoe het werkt, maar eens begonnen met een tutorial die de absolute basics uitlegt over rest-assured. In deze post laat ik zien hoe we op een zo eenvoudig mogelijke manier een API test kunnen maken met […]

APACHE MPM (op *nix servers)

07/11/2017

Benieuwd naar de impact van het wijzigen van Apache MPM Prefork naar Worker? Lees dan door! Bij één van onze klanten heb ik dit onderzocht. Omdat dit ook interessant kan zijn voor anderen, deel ik mijn resultaten en ervaringen graag. Het is misschien wat technisch allemaal, maar voor performancetesters, de doelgroep, is het vast goed […]

Performancetesten en CI/CD, gaat dat samen?

13/10/2017

De afgelopen najaarseditie van Testnet stond onder het thema Continuous Everything vooral stil bij CI/CD en natuurlijk testen. Gezien DevOps en CI/CD ook grote invloed hebben op het vakgebied performance (testen), zijn wij blij dat we vanuit PerformanceArchitecten een bijdrage mochten leveren door middel van het delen van onze visie hierop. Onze collega René Meijboom […]

Een eerste indruk van Gauge

08/09/2017

Tijdens één van onze kennismiddagen hebben we gekeken naar het testtool Gauge. Doel van de sessie was om een beeld te krijgen wat de toegevoegde waarde van Gauge is voor een tester. Benieuwd naar onze ervaringen? Lees dan snel verder! Gauge is een open source project, gesponsord door ThoughtWorks en belooft in het kort het […]

Test Automation Framework BDD

16/06/2017

De afgelopen tijd heb ik in een opdracht collega’s mogen adviseren over de positieve impact van het Test Automation Framework BDD rondom het thema Agile. In een vorige blog ‘Transformation’ is te lezen wat BDD voor mij betekent en hoe BDD voor synergie zorgt tussen verschillende disciplines binnen Agile-teams met als doel het leveren van kwalitatief hoogwaardig […]

Creëer meer eenheid in je SpecFlow steps met Step Argument Transformations

11/04/2017

Laatst kreeg ik de vraag, “Hoe maak je in je testdata onderscheid tussen een regular expression en een gewone tekst”. Oftewel: Hoe beheer je verschillende soorten steps als ze alleen verschillen in de manier waarop data vergeleken wordt. Je hebt een veld en je wilt controleren of er een bepaalde waarde in staat, maar soms […]

SSL/TLS versie en cipher in HP LoadRunner

29/03/2017

In deze blog wil ik even stilstaan bij de resultaten van een performance test die niet overeenkwamen met de verwachtingen die wij als team hadden. Een aantal transacties gingen in responstijd omhoog en het CPU gebruik nam flink toe. Omdat het ons veel tijd heeft gekost, deel ik dit graag met jullie zodat wij performance […]

Regular Expressions en Testautomatisering, twee problemen of juist een oplossing?

25/03/2017

Bij geautomatiseerde checks wil je regelmatig een verwachte waarde controleren tegen een actuele waarde. Vroeg of laat kom je dan in aanraking met wildcards: Je wilt bijvoorbeeld weten of de tekst “Er zijn 42 resultaten gevonden” voorkomt, maar het aantal, hier 42, kan variabel zijn. Van 42 wil je dan een wildcard maken. De meest […]

Automated Approval Testing with Dynamic Data Sets

21/02/2017

For some tests, you’ll need to check if files or documents are the same as they were before, or that they comply with a certain format. When something differs, you need to “reject” or “approve“ them, or even make them the new baseline if you are welcoming the changes. We call this Approval Testing. For more […]

Transformation

20/01/2017

Inmiddels hebben veel organisaties de overstap gemaakt van de traditionele waterval methode naar een iteratieve ontwikkelmethode als Agile/Scrum. Een aantal organisaties zijn in hun werkwijze een stap verder gegaan en hebben DevOps geïntroduceerd. Waar de methodiek Agile vooral focust op het tevredenstellen van de klant, richt DevOps zich daarnaast op het dichten van de kloof […]

Cucumber, Selenium en het gebruik van het Page Object Pattern

14/12/2016

Als je Selenium gebruikt om je testen aan te sturen, kan je gebruik maken van het Page Object Pattern om een laag van abstractie aan te maken: Het maakt een model van je pagina zodat het makkelijker is om acties op die pagina uit te voeren. Dit heeft grote voordelen: Zodra er een wijziging op de […]