API-testen is een cruciale fase in het QA-proces waarbij application program interfaces (API’s) worden geanalyseerd om hun functionaliteit, beveiliging, prestaties en betrouwbaarheid te evalueren.
Met name bij complexe applicaties kan de API bestaan uit tientallen eindpunten en triggers die elkaar beïnvloeden. Om regressieproblemen in de productie te voorkomen, is het zeer nuttig om een reeks end-to-end geautomatiseerde tests te hebben. Voordat deze tests echter worden geïmplementeerd, moeten automation QA (AQA)-ingenieurs en management het framework bepalen waarop deze tests zullen worden gebaseerd.
In dit artikel verkennen en vergelijken we de twee populairste API-testframeworks op de markt: Karate en REST-Assured. Beide frameworks zijn Java-gebaseerd. De geboden vergelijking zal u helpen bij het bepalen welk framework het beste past bij uw specifieke behoeften. Laten we beginnen!
Karate-overzicht
Karate is een relatief nieuw open-source framework waarmee testers, zelfs zonder programmeerachtergrond, API-, webservice- en microservice-testen kunnen uitvoeren. U zou misschien aannemen dat het uit Japan komt, toch? Dit framework is in 2017 ontwikkeld door Peter Thomas en wordt sindsdien wereldwijd door ondernemingen gebruikt.
Laten we dieper ingaan op de details van de Karate-tool. Wat de installatie betreft, is Karate beschikbaar als een enkel, uitvoerbaar JARJAR-bestand. Het kan ook als Maven-afhankelijkheid aan het pom.xml-bestand worden toegevoegd. Als u het niet wilt integreren met een testframework, kunt u kiezen voor de kernversie:
<!-- https://mvnrepository.com/artifact/com.intuit.karate/karate-core -->
<dependency>
<groupId>com.intuit.karate</groupId>
<artifactId>karate-core</artifactId>
<version>1.2.0</version>
</dependency>
Anders zijn er versies die compatibel zijn met de TestNG- en JUnit-testframeworks.
<!-- https://mvnrepository.com/artifact/com.intuit.karate/karate-junit5 -->
<dependency>
<groupId>com.intuit.karate</groupId>
<artifactId>karate-junit5</artifactId>
<version>1.2.0 </version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.intuit.karate/karate-testng -->
<dependency>
<groupId>com.intuit.karate</groupId>
<artifactId>karate-testng</artifactId>
<version>0.8.0.1</version>
</dependency>
Karate maakt gebruik van zijn eigen testscripttaal genaamd “Karate-Script”. Als u ervaring heeft met behavior-driven development (BDD) frameworks zoals Cucumber, zult u merken dat de codestructuur van Karate daar sterk op lijkt:
Feature: sample karate test script
for help, see https://github.com/karatelabs/karate/wiki/IDE-support
Background:
* url 'https://jsonplaceholder.typicode.com/'
Scenario: get all users and then get the first user by id
Given path 'users'
When method get
Then status 200
* def first = response[0]
Given path 'users', first.id
When method get
Then status 200
And assert response.name == "Leanne Graham"
And assert response.email == "[email protected]"
Karate deelt inderdaad veel overeenkomsten met Cucumber:
- keywords zoals “Feature”, “Scenario”, “Given”, “When”, “Then”, “And”
- het opslaan van tests in .feature-bestanden
Het belangrijkste onderscheidende kenmerk van Karate is echter dat “alle step definitions al voor ons geschreven zijn”. Dit is met name voordelig voor API-testen. In tegenstelling tot UI-testen volgt API-testen doorgaans een uniform schema:
- Background
- Het aanleveren van request parameters
- Validatie van de response status
Het is dus erg logisch om vooraf voorbereide step definitions te gebruiken in plaats van zelf eigen definities te creëren. Laten we nu bekijken hoe Karate omgaat met alle drie de genoemde stappen.
Achtergrond
Achtergrond bevat meestal gemeenschappelijke eigenschappen die gedeeld worden door alle scenario’s in het .feature-bestand. Sommige van deze eigenschappen zijn al vooraf gedefinieerd, zoals de URL:
Background:
* url 'https://jsonplaceholder.typicode.com'
En u kunt variabelen rechtstreeks in het feature-bestand definiëren met het trefwoord “def”:
* def user =
"""
{
"name": "Test User",
"username": "testuser",
"email": "[email protected]",
"address": {
"street": "Has No Name",
"suite": "Apt. 123",
"city": "Electri",
"zipcode": "54321-6789"
}
}
"""
Requestparameters verstrekken
Allereerst moeten we een pad bieden dat ook queryparameters kan bevatten, gescheiden door komma’s.
Given path 'users', 1234
Vervolgens kunnen we, indien nodig, de request payload toevoegen, die zowel JSON- als XML-formaten ondersteunt.
JSON:
And request
{
"name":"Vidhya",
"age":29,"locale":"en",
"twitter":"VidhyaJava",
"email":"[email protected]"
}
XML:
* def payload =
"""
<note>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend!</body>
</note>
"""
And request payload
Tot slot specificeren we de HTTP-methode voor de aanvraag, die een van de volgende kan zijn: get, post, delete, patch of put.
When method get
Validatie van respons
Allereerst valideren we de respons code voor zowel positieve (200, 201) als negatieve (4xx) testgevallen.
Then status 201
Then status 404
Vervolgens gaan we verder met de validatie van het responseschema, waarbij we de response payload kunnen verifiëren in zowel JSON- als XML-indeling. In het geval van JSON:
{
"id": 1,
"name": "Leanne Graham",
"username": "Bret",
"email": "[email protected]",
"address": {
"street": "Kulas Light",
"suite": "Apt. 556",
"city": "Gwenborough",
"zipcode": "92998-3874",
"geo": {
"lat": "-37.3159",
"lng": "81.1496"
}
},
"phone": "1-770-736-8031 x56442",
"website": "hildegard.org",
"company": {
"name": "Romaguera-Crona",
"catchPhrase": "Multi-layered client-server neural-net",
"bs": "harness real-time e-markets"
}
}
Als we specifieke eigenschappen willen valideren, kunnen de assertions het volgende omvatten:
And assert response.name == "Leanne Graham"
And assert response.email == "[email protected]"
Echter, het is belangrijk om op te merken dat Karate een ingebouwd mechanisme biedt om de volledige JSON-respons te valideren, in tegenstelling tot REST-Assured:
And match response == {
"id":1,"name":"LeanneGraham","username":"Bret",
"email":"[email protected]",
"address":{"street":"Kulas Light","suite":"Apt. 556",
"city":"Gwenborough","zipcode":"92998-3874",
"geo":{"lat":"-37.3159","lng":"81.1496"}},
"phone":"1-770-736-8031x56442",
"website":"hildegard.org",
"company":{
"name":"Romaguera-Crona",
"catchPhrase":"Multi-layered client-server neural-net",
"bs":"harness real-time e-markets"
}
}
Karate bevat een ingebouwde rapportagetool die rapporten genereert in de map targetkarate-reports. Het hoofdrapportbestand is karate-summary.html:
Overzicht van REST-Assured
REST-Assured is een Java-gebaseerde bibliotheek, gemaakt door JayWay Company, om het testen en valideren van RESTful webservices te stroomlijnen. Het dient als een efficiënte katalysator voor het automatiseren van het testproces van REST API’s.
REST-Assured kan eenvoudig worden geïnstalleerd door de Maven dependency toe te voegen:
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<version>5.1.1</version>
<scope>test</scope>
</dependency>
Een testframework zoals JUnit of TestNG is vereist als testrunner. Het onderstaande codevoorbeeld demonstreert het gebruik van JUnit. Laten we nu eens kijken naar een testcase gebaseerd op REST-Assured:
public class UsersTest {
@Before
public void setup() {
RestAssured.baseURI = "https://jsonplaceholder.typicode.com/";
}
@Test
public void getAllUsersAndThenGetFirstUserById() {
Response responseAllUsers =
given()
.when()
.get("/users")
.then()
.statusCode(200)
.extract()
.response();
int firstUserId = responseAllUsers.jsonPath().getInt("id[0]");
Response responseFirstUser =
given()
.pathParam("id", firstUserId)
.when()
.get("/users/{id}")
.then()
.statusCode(200)
.extract()
.response();
Assert.assertEquals(responseFirstUser.jsonPath().getString("name"),
"Leanne Graham");
Assert.assertEquals(responseFirstUser.jsonPath().getString("email"),
"[email protected]");
}
}
We zien dat tests gebaseerd op REST-Assured zijn geschreven in een BDD-stijl, volgens de Given-When-Then structuur. Echter, in tegenstelling tot Karate, zijn deze tests ingebed in de Java-code. Met andere woorden, om de geïmplementeerde testcases te bekijken, moet men de API-tests induiken en de code onderzoeken. Standaard gebruikt REST-Assured geen .feature-bestanden, hoewel het geïntegreerd kan worden met tools zoals Cucumber of andere BDD-frameworks.
REST-Assured verwerkt de stadia van de API-testschema’s op de volgende manier (met het voorbeeld van het JUnit-testframework):
Achtergrond
We kunnen simpelweg de @Before annotatie gebruiken:
@Before
public void setup() {
RestAssured.baseURI = "https://jsonplaceholder.typicode.com";
}
Requestparameters verstrekken
Dit stadium is opgedeeld in 2 delen door de trefwoorden given() en when().
- Met given() kunnen we de content-type en de request body opgeven, indien nodig. Het is mogelijk om JSON- of XML-payloads door te geven aan een String-object:
public void createUser() {
String body = "{"name": "Test User"," +
""username": "testuser", " +
""email": "[email protected]"," +
""address": " +
"{ "street": "Has No Name"," +
""suite": "Apt. 123"," +
""city": "Electri"," +
""zipcode": "54321-6789"}}";
Response response =
given()
.contentType(ContentType.JSON)
.body(body)
Een nauwkeurigere aanpak is het gebruik van Object Mapping bij het werken met REST-Assured. Definieer het request payload-schema in de juiste klasse:
public static class User {
private String name;
private String username;
public User(String name, String username) {
this.name = name;
this.username = username;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getUsername() {
return username;
}
public void setUsername(String job) {
this.username = username;
}
}
Vervolgens kunt u eenvoudig een nieuwe instantie van de klasse doorgeven aan de request payload:
@Test
public void createUser() {
User user = new User("Test User", "testuser");
Response response =
given()
.contentType(ContentType.JSON)
.body(user)
Als alternatief kunnen we de payload rechtstreeks uit een bestand importeren:
@Test
public void createUserXML() {
File xmlDataInFile = new File("src/test/resources/user.xml");
Response response =
given()
.contentType(ContentType.XML)
.body(xmlDataInFile)
- Met when() moeten we het pad en de methode specificeren:
.when()
.get("/users")
Het pad in REST-Assured accepteert ook variabelen:
int firstUserId = 123;
*********************
.pathParam("id", firstUserId)
.when()
.get("/users/{id}")
Validatie van respons
Validatie van de respons gebeurt met het trefwoord then(). Ten eerste valideren we meestal de statuscode van de respons:
.then()
.statusCode(200)
Daarna kunnen we doorgaan met het extraheren van het respons-object:
.extract()
.response();
en enkele van zijn eigenschappen valideren:
Assert.assertEquals(responseFirstUser.jsonPath().getString("name"), "Leanne Graham");
Assert.assertEquals(responseFirstUser.jsonPath().getString("email"), "[email protected]");
Wat betreft rapportage, biedt REST-Assured geen ingebouwde rapportagetool. Daarom is het noodzakelijk om een geschikte externe rapportagelibrary te gebruiken, zoals Allure Report.
Karate vs REST-Assured
Nou, het is tijd om twee gegeven tools te vergelijken en te beslissen welke we voor onze specifieke behoeften moeten kiezen. Laten we hun prestaties vergelijken voor het eenvoudige testscenario dat hierboven is genoemd:
Zoals we kunnen zien, kost het uitvoeren van Karate veel minder tijd dan REST-Assured in het geval van een enkel scenario. Echter, bij het overwegen van meerdere scenario’s (d.w.z. de gehele testscope), kunnen we verwachten dat het verschil niet zo significant zal zijn.
De vergelijking van de twee frameworks op basis van andere belangrijke criteria wordt gepresenteerd in de onderstaande tabel:
BDD-syntaxis
Ja
Ja
Test-scripting taal
Karate-Script (Gherkin)
Java
Valideer gehele JSON-respons
Ja
Nee (extra Java-bibliotheek vereist)
Testrunner
Optioneel (JUnit, TestNG)
Vereist (JUnit, TestNG)
Opnieuw proberen
Ja
Nee (extra Java-bibliotheek vereist)
Rapportagetool
Ingebouwd
Externe tool vereist (Allure Report, etc.)
Lees bestand
Ja
Nee (extra Java-bibliotheek vereist)
Prestatietesten
Ja (mogelijk om Karate-tests en Gatling-tests te hergebruiken)
No
Zowel Karate als REST-Assured testtools hebben hun sterke en zwakke punten. Over het algemeen heeft Karate een groter aantal ingebouwde tools in vergelijking met REST-Assured. Dit betekent dat u kunt beginnen met het schrijven van tests zonder extra tijd te besteden aan het configureren van externe bibliotheken. Bovendien gebruikt Karate een eenvoudige en directe testscripttaal, waardoor het geschikt is voor teams met beperkte Java-ervaring. Als u tevreden bent met de standaardrapporten van Karate en geen tijd wilt investeren in het configureren van aangepaste rapporten, kan dit een betere keuze zijn.
REST-Assured vereist daarentegen een sterke Java-achtergrond van het QA Automation-team en het gebruik van extra bibliotheken. In het geval van complexe en sterk aangepaste API’s kan REST-Assured echter een betere keuze zijn. Het schrijven van tests direct in Java kan in dergelijke gevallen eenvoudiger zijn.
REST-Assured maakt ook gebruik van bibliotheken zoals Hamcrest matchers, wat meer opties biedt voor aanvullende validatie in specifieke scenario’s. Als u liever BDD gebruikt en de kant-en-klare step definitions van Karate niet aan uw vereisten voldoen, kan REST-Assured worden gebruikt in combinatie met een externe BDD-tool zoals Cucumber.
Laatste gedachten
Concluderend is het vermeldenswaardig dat zowel Karate als REST-Assured tools actief worden ontwikkeld en goed gedocumenteerd zijn. Uiteindelijk moet de keuze tussen Karate en REST-Assured gebaseerd zijn op factoren zoals de complexiteit van uw API, de mate van Java-expertise binnen uw team, de behoefte aan specifieke validatie- of aanpassingsopties en uw voorkeursaanpak voor testen (bijv. BDD).
Met de bovenstaande informatie kunt u een weloverwogen beslissing nemen over welke tool het beste bij uw specifieke behoeften past. Succes!