REST API-testen met komkommer

1. Overzicht

Deze tutorial geeft een inleiding tot Cucumber, een veelgebruikte tool voor het testen van gebruikersacceptatie, en het gebruik ervan in REST API-tests.

Om het artikel op zichzelf staand en onafhankelijk van externe REST-services te maken, zullen we bovendien WireMock gebruiken, een stubbing en spottende webservicebibliotheek. Als u meer wilt weten over deze bibliotheek, raadpleegt u de inleiding tot WireMock.

2. Augurk - de taal van komkommer

Cucumber is een testraamwerk dat Behavior Driven Development (BDD) ondersteunt, waardoor gebruikers toepassingsbewerkingen in platte tekst kunnen definiëren. Het werkt op basis van de Gherkin Domain Specific Language (DSL). Deze eenvoudige maar krachtige syntaxis van Gherkin stelt ontwikkelaars en testers in staat complexe tests te schrijven, terwijl deze begrijpelijk blijft voor zelfs niet-technische gebruikers.

2.1. Inleiding tot augurk

Augurk is een lijngeoriënteerde taal die regeleinden, inspringingen en trefwoorden gebruikt om documenten te definiëren. Elke niet-lege regel begint meestal met een augurk-trefwoord, gevolgd door een willekeurige tekst, meestal een beschrijving van het trefwoord.

De hele structuur moet in een bestand worden geschreven met de extensie voorzien zijn van extensie om te worden herkend door komkommer.

Hier is een eenvoudig voorbeeld van een augurkdocument:

Feature: Een korte omschrijving van de gewenste functionaliteit Scenario: Een bedrijfssituatie Gegeven een randvoorwaarde En nog een randvoorwaarde Wanneer er een gebeurtenis plaatsvindt En er gebeurt ook nog een gebeurtenis Dan wordt een toetsbare uitkomst bereikt En wordt er ook iets anders afgerond

In de volgende secties beschrijven we een aantal van de belangrijkste elementen in een augurkstructuur.

2.2. Voorzien zijn van

We gebruiken een augurkbestand om een ​​toepassingsfunctie te beschrijven die moet worden getest. Het bestand bevat de Voorzien zijn van trefwoord aan het begin, gevolgd door de naam van het element op dezelfde regel en een optionele beschrijving die meerdere regels eronder kan beslaan.

Komkommer-parser slaat alle tekst over, behalve de Voorzien zijn van trefwoord, en neemt het alleen op voor documentatiedoeleinden.

2.3. Scenario's en stappen

Een augurkstructuur kan bestaan ​​uit een of meer scenario's, te herkennen aan de Scenario trefwoord. Een scenario is in feite een test waarmee gebruikers een mogelijkheid van de applicatie kunnen valideren. Het moet een initiële context beschrijven, gebeurtenissen die kunnen plaatsvinden en verwachte resultaten die door die gebeurtenissen worden gecreëerd.

Deze dingen worden gedaan met behulp van stappen, geïdentificeerd door een van de vijf sleutelwoorden: Gegeven, Wanneer, Dan, En, en Maar.

  • Gegeven: Deze stap is om het systeem in een goed gedefinieerde staat te brengen voordat gebruikers met de applicatie gaan werken. EEN Gegeven clausule kan worden beschouwd als een voorwaarde voor de use case.
  • Wanneer: EEN Wanneer stap wordt gebruikt om een ​​gebeurtenis te beschrijven die met de toepassing plaatsvindt. Dit kan een actie zijn die door gebruikers is ondernomen, of een gebeurtenis die wordt geactiveerd door een ander systeem.
  • Dan: Deze stap is om een ​​verwacht resultaat van de test te specificeren. Het resultaat moet verband houden met de zakelijke waarden van de te testen functie.
  • En en Maar: Deze trefwoorden kunnen worden gebruikt om de bovenstaande stapsleutelwoorden te vervangen als er meerdere stappen van hetzelfde type zijn.

Komkommer onderscheidt deze trefwoorden niet echt, maar ze zijn er nog steeds om de functie leesbaarder te maken en consistent te maken met de BDD-structuur.

3. Komkommer-JVM-implementatie

Cucumber is oorspronkelijk geschreven in Ruby en is overgezet naar Java met de Cucumber-JVM-implementatie, die het onderwerp is van deze sectie.

3.1. Afhankelijkheden van Maven

Om gebruik te kunnen maken van Cucumber-JVM in een Maven-project, moet de volgende afhankelijkheid in de POM worden opgenomen:

 io.cucumber cucumber-java 6.8.0 test 

Om JUnit-testen met Cucumber te vergemakkelijken, hebben we nog een afhankelijkheid nodig:

 io. komkommer komkommer-junit 6.8.0 

Als alternatief kunnen we een ander artefact gebruiken om te profiteren van lambda-expressies in Java 8, die in deze tutorial niet worden behandeld.

3.2. Stap Definities

Augurkscenario's zouden nutteloos zijn als ze niet in acties werden vertaald, en dit is waar stapdefinities een rol gaan spelen. Kort gezegd is een stapdefinitie een geannoteerde Java-methode met een bijgevoegd patroon waarvan de taak is om augurkenstappen in platte tekst om te zetten in uitvoerbare code. Na het ontleden van een feature-document, zal Cucumber zoeken naar stapdefinities die overeenkomen met vooraf gedefinieerde Gherkin-stappen om uit te voeren.

Laten we, om het duidelijker te maken, de volgende stap bekijken:

Gezien ik een cursus heb ingeschreven in Baeldung

En een stapdefinitie:

@Given ("Ik heb een cursus geregistreerd in Baeldung") public void verifyAccount () {// methode implementatie}

Wanneer Komkommer de gegeven stap leest, zoekt het naar stapdefinities waarvan de annotatiepatronen overeenkomen met de augurken-tekst.

4. Tests maken en uitvoeren

4.1. Een functiebestand schrijven

Laten we beginnen met het declareren van scenario's en stappen in een bestand waarvan de naam eindigt op de .voorzien zijn van uitbreiding:

Functie: een REST API testen Gebruikers moeten in staat zijn om GET- en POST-verzoeken in te dienen bij een webservice, vertegenwoordigd door WireMock Scenario: gegevens uploaden naar een webservice Wanneer gebruikers gegevens uploaden over een project Dan moet de server het afhandelen en een successtatus retourneren Scenario: gegevens ophalen uit een webservice Wanneer gebruikers informatie willen krijgen over het 'Cucumber'-project, worden de gevraagde gegevens geretourneerd

We slaan dit bestand nu op in een map met de naam Voorzien zijn van, op voorwaarde dat de map tijdens runtime in het klassenpad wordt geladen, bijv. src / main / resources.

4.2. JUnit configureren om met komkommer te werken

Om ervoor te zorgen dat JUnit op de hoogte is van Cucumber en feature-bestanden leest tijdens het draaien, moet het Komkommer klasse moet worden gedeclareerd als de Loper. We moeten JUnit ook vertellen waar het moet zoeken naar feature-bestanden en stapdefinities.

@RunWith (Cucumber.class) @CucumberOptions (features = "classpath: Feature") openbare klasse CucumberIntegrationTest {}

Zoals u kunt zien, is de Kenmerken element van Komkommer Optie lokaliseert het feature-bestand dat eerder is gemaakt. Een ander belangrijk element, genaamd lijm, biedt paden naar stapdefinities. Als de testcase- en stapdefinities zich echter in hetzelfde pakket bevinden als in deze zelfstudie, kan dat element worden verwijderd.

4.3. Stapdefinities schrijven

Wanneer Cucumber stappen parseert, zoekt het naar methoden die zijn geannoteerd met Gherkin-sleutelwoorden om de overeenkomende stapdefinities te vinden.

De uitdrukking van een stapdefinitie kan een reguliere uitdrukking of een komkommeruitdrukking zijn. In deze tutorial gebruiken we Cucumber Expressions.

Het volgende is een methode die volledig overeenkomt met een augurkstap. De methode wordt gebruikt om gegevens naar een REST-webservice te posten:

@When ("gebruikers uploaden gegevens op een project") public void usersUploadDataOnAProject () gooit IOException {}

En hier is een methode die overeenkomt met een augurkstap en een argument uit de tekst haalt, die zal worden gebruikt om informatie van een REST-webservice te krijgen:

@When ("users want to get information on the {string} project") public void usersGetInformationOnAProject (String projectName) gooit IOException {}

Zoals u kunt zien, is de usersGetInformationOnAProject methode duurt een Draad argument, wat de projectnaam is. Dit argument wordt verklaard door {draad} in de annotatie en hier komt het overeen met Komkommer in de staptekst.

Als alternatief kunnen we een reguliere expressie gebruiken:

@When ("^ gebruikers willen informatie krijgen over het '(. +)' Project $") public void usersGetInformationOnAProject (String projectName) gooit IOException {}

Merk op ‘^' en ‘$' die het begin en het einde van de regex dienovereenkomstig aangeven. Terwijl ‘(.+)' komt overeen met de Draad parameter.

In de volgende sectie geven we de werkende code voor beide bovenstaande methoden.

4.4. Tests maken en uitvoeren

Eerst beginnen we met een JSON-structuur om de gegevens te illustreren die naar de server zijn geüpload door een POST-verzoek en die naar de client zijn gedownload met behulp van een GET. Deze structuur wordt opgeslagen in het jsonString veld, en hieronder weergegeven:

{"testing-framework": "komkommer", "ondersteunde taal": ["Ruby", "Java", "Javascript", "PHP", "Python", "C ++"], "website": "komkommer. io "}

Om een ​​REST API te demonstreren, gebruiken we een WireMock-server:

WireMockServer wireMockServer = nieuwe WireMockServer (opties (). DynamicPort ());

Daarnaast gebruiken we Apache HttpClient API om de client weer te geven die wordt gebruikt om verbinding te maken met de server:

CloseableHttpClient httpClient = HttpClients.createDefault ();

Laten we nu verder gaan met het schrijven van testcode binnen stapdefinities. We zullen dit doen voor de usersUploadDataOnAProject methode eerst.

De server moet draaien voordat de client er verbinding mee maakt:

wireMockServer.start ();

De WireMock API gebruiken om de REST-service te stubben:

configureFor ("localhost", wireMockServer.port ()); stubFor (post (urlEqualTo ("/ create")) .withHeader ("content-type", equalTo ("application / json")) .withRequestBody (met ("testing-framework")) .willReturn (aResponse (). withStatus (200)));

Stuur nu een POST-verzoek met de inhoud uit het jsonString veld hierboven aangegeven aan de server:

HttpPost request = nieuwe HttpPost ("// localhost:" + wireMockServer.port () + "/ create"); StringEntity entiteit = nieuwe StringEntity (jsonString); request.addHeader ("content-type", "application / json"); request.setEntity (entiteit); HttpResponse response = httpClient.execute (verzoek);

De volgende code geeft aan dat het POST-verzoek met succes is ontvangen en afgehandeld:

assertEquals (200, response.getStatusLine (). getStatusCode ()); verifieer (postRequestedFor (urlEqualTo ("/ create")) .withHeader ("content-type", equalTo ("application / json")));

De server moet stoppen nadat deze is gebruikt:

wireMockServer.stop ();

De tweede methode die we hierin zullen implementeren is usersGetInformationOnAProject (String projectnaam). Net als bij de eerste test, moeten we de server starten en vervolgens de REST-service stubben:

wireMockServer.start (); configureFor ("localhost", wireMockServer.port ()); stubFor (get (urlEqualTo ("/ projects / cucumber")) .withHeader ("accept", equalTo ("application / json")) .willReturn (aResponse (). withBody (jsonString)));

Een GET-verzoek indienen en een antwoord ontvangen:

HttpGet request = nieuwe HttpGet ("// localhost:" + wireMockServer.port () + "/ projects /" + projectName.toLowerCase ()); request.addHeader ("accept", "application / json"); HttpResponse httpResponse = httpClient.execute (verzoek);

We zullen het httpResponse variabele naar een Draad met behulp van een hulpmethode:

String responseString = convertResponseToString (httpResponse);

Hier is de implementatie van die conversiehulpmethode:

private String convertResponseToString (HttpResponse response) gooit IOException {InputStream responseStream = response.getEntity (). getContent (); Scannerscanner = nieuwe scanner (responseStream, "UTF-8"); String responseString = scanner.useDelimiter ("\ Z"). Next (); scanner.close (); return responseString; }

Het volgende verifieert het hele proces:

assertThat (responseString, containsString ("\" testing-framework \ ": \" komkommer \ "")); assertThat (responseString, containsString ("\" website \ ": \" cucumber.io \ "")); verifieer (getRequestedFor (urlEqualTo ("/ projects / cucumber")) .withHeader ("accept", equalTo ("application / json")));

Stop ten slotte de server zoals eerder beschreven.

5. Functies parallel uitvoeren

Cucumber-JVM ondersteunt native parallelle testuitvoering over meerdere threads. We gebruiken JUnit samen met de Maven Failsafe-plug-in om de hardlopers uit te voeren. Als alternatief kunnen we Maven Surefire gebruiken.

JUnit voert de feature-bestanden parallel uit in plaats van scenario's, wat betekent alle scenario's in een feature-bestand worden uitgevoerd door dezelfde thread.

Laten we nu de configuratie van de plug-in toevoegen:

 maven-failsafe-plugin $ {maven-failsafe-plugin.version} CucumberIntegrationTest.java methoden 2 integratietest verifiëren 

Let daar op:

  • parallel: kan zijn klassen, methoden, of beide - in ons geval, klassen zorgt ervoor dat elke testklasse in een aparte thread wordt uitgevoerd
  • draad tellen: geeft aan hoeveel threads moeten worden toegewezen voor deze uitvoering

Dat is alles wat we hoeven te doen om de Cucumber-functies parallel uit te voeren.

6. Conclusie

In deze tutorial hebben we de basisprincipes van Cucumber besproken en hoe dit framework de domeinspecifieke taal Gherkin gebruikt voor het testen van een REST API.

Zoals gewoonlijk zijn alle codevoorbeelden die in deze tutorial worden getoond, beschikbaar op GitHub.


$config[zx-auto] not found$config[zx-overlay] not found