Gegevenstabellen voor komkommers

1. Inleiding

Cucumber is een Behavioral Driven Development (BDD) -raamwerk waarmee ontwikkelaars op tekst gebaseerde testscenario's kunnen maken met behulp van de Gherkin-taal. In veel gevallen vereisen deze scenario's nepgegevens om een ​​functie uit te oefenen, die lastig kan zijn om te injecteren, vooral bij complexe of meervoudige invoer.

In deze zelfstudie bekijken we hoe u Cucumber-gegevenstabellen kunt gebruiken om nepgegevens op een leesbare manier op te nemen.

2. Scenario-syntaxis

Bij het definiëren van komkommerscenario's injecteren we vaak testgegevens die door de rest van het scenario worden gebruikt:

Scenario: correct niet-nul aantal boeken gevonden door auteur Gegeven dat ik een boek in de winkel heb genaamd The Devil in the White City door Erik Larson Wanneer ik naar boeken zoek op auteur Erik Larson Dan vind ik 1 boek

2.1. Gegevenstabellen

Hoewel inline gegevens voldoende zijn voor een enkel boek, kan ons scenario onoverzichtelijk worden wanneer meerdere boeken worden toegevoegd. Om dit af te handelen, maken we een gegevenstabel in ons scenario:

Scenario: correct aantal boeken dat niet gelijk is aan nul, gevonden door auteur Gegeven dat ik de volgende boeken in de winkel heb | De duivel in de witte stad | Erik Larson | | De leeuw, de heks en de kleerkast | C.S. Lewis | | In the Garden of Beasts | Erik Larson | Als ik naar boeken zoek op auteur Erik Larson, dan vind ik 2 boeken

We definiëren onze gegevenstabel als een onderdeel van onze Gegeven clausule door het inspringen van de tabel onder de tekst van het Gegeven clausule. Met behulp van deze gegevenstabel kunnen we een willekeurig aantal boeken - inclusief slechts één boek - aan onze winkel toevoegen door rijen toe te voegen of te verwijderen.

Bovendien, gegevenstabellen kunnen met elke clausule worden gebruikt - niet alleen Gegeven clausules.

2.2. Met inbegrip van koppen

Het is duidelijk dat de eerste kolom de titel van het boek vertegenwoordigt en de tweede kolom de auteur van het boek. De betekenis van elke kolom is echter niet altijd zo duidelijk.

Wanneer verduidelijking nodig is, we kunnen een koptekst toevoegen door een nieuwe eerste rij toe te voegen:

Scenario: correct aantal boeken dat niet gelijk is aan nul, gevonden door auteur Gegeven dat ik de volgende boeken in de winkel heb | titel | auteur | | De duivel in de witte stad | Erik Larson | | De leeuw, de heks en de kleerkast | C.S. Lewis | | In the Garden of Beasts | Erik Larson | Als ik naar boeken zoek op auteur Erik Larson, dan vind ik 2 boeken

Hoewel de koptekst gewoon een andere rij in de tabel lijkt te zijn, deze eerste rij heeft een bijzondere betekenis wanneer we onze tabel ontleden in een lijst met kaarten in de volgende sectie.

3. Stapdefinities

Nadat we ons scenario hebben gemaakt, implementeren we het Gegeven stap definitie. In het geval van een stap die een gegevenstabel bevat, we implementeren onze methoden met een Data tafel argument:

@Given ("some phrase") public void somePhrase (gegevenstabel) {// ...}

De Data tafel object bevat de tabelgegevens uit de gegevenstabel die we in ons scenario hebben gedefinieerd, evenals methoden om deze gegevens om te zetten in bruikbare informatie. Over het algemeen zijn er drie manieren om een ​​gegevenstabel in Cucumber te transformeren: (1) een lijst met lijsten, (2) een lijst met kaarten en (3) een tabeltransformator.

Om elke techniek te demonstreren, gebruiken we een simpele Boek domeinklasse:

openbare klasse Book {private String title; private String-auteur; // standaard constructeurs, getters & setters ...}

Bovendien maken we een Boekwinkel klasse die beheert Boek voorwerpen:

openbare klasse BookStore {privélijstboeken = nieuwe ArrayList (); public void addBook (Boek boek) {books.add (boek); } public void addAllBooks (collectieboeken) {this.books.addAll (boeken); } openbare lijst booksByAuthor (String auteur) {return books.stream () .filter (boek -> Objects.equals (auteur, book.getAuthor ())) .collect (Collectors.toList ()); }}

Voor elk van de volgende scenario's beginnen we met een basisstapdefinitie:

openbare klasse BookStoreRunSteps {privé BookStore-winkel; privélijst gevonden boeken; @Before public void setUp () {store = new BookStore (); foundBooks = nieuwe ArrayList (); } // When & Then-definities ...}

3.1. Lijst met lijsten

De eenvoudigste methode voor het verwerken van tabelgegevens is het converteren van het Data tafel argument in een lijst met lijsten. We kunnen een tabel zonder koptekst maken om te demonstreren:

Scenario: Correct niet-nul aantal boeken gevonden door auteur per lijst Gegeven dat ik de volgende boeken in de winkel heb per lijst | De duivel in de witte stad | Erik Larson | | De leeuw, de heks en de kleerkast | C.S. Lewis | | In the Garden of Beasts | Erik Larson | Als ik naar boeken zoek op auteur Erik Larson, dan vind ik 2 boeken

Komkommer zet de bovenstaande tabel om in een lijst met lijsten door elke rij te behandelen als een lijst met kolomwaarden. Dus, Cucumber parseert elke rij in een lijst met de boektitel als het eerste element en de auteur als het tweede:

[["The Devil in the White City", "Erik Larson"], ["The Lion, the Witch and the Wardrobe", "C.S. Lewis"], ["In the Garden of Beasts", "Erik Larson"]]

Wij gebruiken de asLists methode - het leveren van een String.class argument - om het Data tafel argument tegen een Lijst. Dit Klasse argument informeert de asLists methode welk gegevenstype we van elk element verwachten. In ons geval willen we dat de titel en auteur zijn Draad waarden. Zo leveren wij String.class:

@Given ("^ Ik heb de volgende boeken in de winkel op lijst $") public void haveBooksInTheStoreByList (DataTable-tabel) {List rijen = table.asLists (String.class); voor (Lijstkolommen: rijen) {store.addBook (nieuw boek (columns.get (0), columns.get (1))); }}

We herhalen vervolgens elk element van de sublijst en maken een overeenkomstig Boek voorwerp. Ten slotte voegen we elk gemaakt Boek bezwaar maken tegen onze Boekwinkel voorwerp.

Als we gegevens met een kop hebben geparseerd, we zouden de eerste rij overslaan omdat Komkommer geen onderscheid maakt tussen koppen en rijgegevens voor een lijst met lijsten.

3.2. Lijst met kaarten

Hoewel een lijst met lijsten een fundamenteel mechanisme biedt voor het extraheren van elementen uit een gegevenstabel, kan de stapimplementatie cryptisch zijn. Komkommer biedt een lijst met kaartenmechanismen als een beter leesbaar alternatief.

In dit geval, we moeten een richting aangeven voor onze tafel:

Scenario: correct niet-nul aantal boeken gevonden door auteur op kaart Gegeven dat ik de volgende boeken in de winkel heb op kaart | titel | auteur | | De duivel in de witte stad | Erik Larson | | De leeuw, de heks en de kleerkast | C.S. Lewis | | In the Garden of Beasts | Erik Larson | Als ik naar boeken zoek op auteur Erik Larson, dan vind ik 2 boeken

Net als bij het lijst met lijsten-mechanisme, maakt Cucumber een lijst met elke rij, maar in plaats daarvan wijst de kolomkop toe aan elke kolomwaarde. Komkommer herhaalt dit proces voor elke volgende rij:

[{"title": "The Devil in the White City", "author": "Erik Larson"}, {"title": "The Lion, the Witch and the Wardrobe", "author": "CS Lewis"} , {"title": "In the Garden of Beasts", "author": "Erik Larson"}]

Wij gebruiken de asMaps methode - twee leveren String.class arguments - om het Data tafel argument tegen een Lijst. Het eerste argument geeft het gegevenstype van de sleutel (header) aan en het tweede geeft het gegevenstype van elke kolomwaarde aan. We leveren er dus twee String.class argumenten omdat onze headers (sleutel) en titel en auteur (waarden) allemaal zijn Draads.

Vervolgens herhalen we elk Kaart object en extraheer elke kolomwaarde met de kolomkop als sleutel:

@Given ("^ Ik heb de volgende boeken in de winkel per kaart $") public void haveBooksInTheStoreByMap (DataTable-tabel) {List rijen = table.asMaps (String.class, String.class); voor (Kaartkolommen: rijen) {store.addBook (nieuw boek (columns.get ("titel"), columns.get ("auteur"))); }}

3.3. Tafeltransformator

Het laatste (en meest uitgebreide) mechanisme voor het converteren van gegevenstabellen naar bruikbare objecten is het maken van een Tafeltransformator. EEN Tafeltransformator is een object dat Cucumber instrueert hoe een Data tafel bezwaar maken tegen het gewenste domeinobject:

Laten we een voorbeeldscenario bekijken:

Scenario: Correct aantal boeken dat niet nul is, gevonden door auteur met transformator Gegeven dat ik de volgende boeken in de winkel heb met transformator | titel | auteur | | De duivel in de witte stad | Erik Larson | | De leeuw, de heks en de kleerkast | C.S. Lewis | | In the Garden of Beasts | Erik Larson | Als ik naar boeken zoek op auteur Erik Larson, dan vind ik 2 boeken

Hoewel een lijst met kaarten, met de bijbehorende kolomgegevens, nauwkeuriger is dan een lijst met lijsten, maken we onze stapdefinitie nog steeds vol met conversielogica. In plaats daarvan, we moeten onze stap definiëren met het gewenste domeinobject (in dit geval een Boekcatalogus) als argument:

@Given ("^ Ik heb de volgende boeken in de winkel met transformator $") public void haveBooksInTheStoreByTransformer (BookCatalog-catalogus) {store.addAllBooks (catalog.getBooks ()); }

Om dit te doen, we moeten een aangepaste implementatie maken van het TypRegistryConfigurer koppel.

Deze implementatie moet twee dingen uitvoeren:

  1. Maak een nieuw Tafeltransformator implementatie.
  2. Registreer deze nieuwe implementatie met de configureTypeRegistry methode.

Om het Data tafel in een bruikbaar domeinobject, maken we een Boekcatalogus klasse:

openbare klasse BookCatalog {privélijstboeken = nieuwe ArrayList (); public void addBook (Boek boek) {books.add (boek); } // standaard getter ...}

Laten we, om de transformatie uit te voeren, het TypRegistryConfigurer koppel:

openbare klasse BookStoreRegistryConfigurer implementeert TypeRegistryConfigurer {@Override public Locale locale () {return Locale.ENGLISH; } @Override public void configureTypeRegistry (TypeRegistry typeRegistry) {typeRegistry.defineDataTableType (nieuwe DataTableType (BookCatalog.class, nieuwe BookTableTransformer ())); } // ...

en implementeer vervolgens het Tafeltransformator interface voor onze Boekcatalogus klasse:

 privé statische klasse BookTableTransformer implementeert TableTransformer {@Override openbare BookCatalog-transformatie (gegevenstabel-tabel) gooit Throwable {BookCatalog-catalogus = nieuwe BookCatalog (); table.cells () .stream () .skip (1) // Sla koptekstrij .map over (velden -> nieuw boek (fields.get (0), fields.get (1))) .forEach (catalog :: addBook ); catalogus retourneren; }}}

Merk op dat we Engelse gegevens uit de tabel transformeren, en daarom retourneren we de Engelse landinstelling van onze landinstelling () methode. Bij het ontleden van gegevens in een andere landinstelling, moeten we verander het retourtype van het landinstelling () methode naar de juiste landinstelling.

Omdat we een koptekst van een gegevenstabel in ons scenario hebben opgenomen, we moeten de eerste rij overslaan als we door de tabelcellen gaan (vandaar de overslaan (1) bellen). We zouden de overslaan (1) bel als onze tafel geen koptekst bevatte.

Standaard is het De lijmcode die aan een test is gekoppeld, wordt verondersteld zich in hetzelfde pakket te bevinden als de klasse Runner. Daarom is er geen aanvullende configuratie nodig als we onze BookStoreRegistryConfigurer in hetzelfde pakket als onze runner class. Als we de configurer in een ander pakket toevoegen, we moeten het pakket expliciet opnemen in het @CucumberOptionslijm veld- voor de hardlopersklasse.

4. Conclusie

In dit artikel hebben we gekeken hoe we een augurk-scenario met tabelgegevens kunnen definiëren met behulp van een gegevenstabel. Daarnaast hebben we drie manieren onderzocht om een ​​stapdefinitie te implementeren die een Cucumber-gegevenstabel verbruikt.

Hoewel een lijst met lijsten en een lijst met kaarten voldoende zijn voor basistabellen, biedt een tabeltransformator een veel rijker mechanisme dat in staat is om complexere gegevens te verwerken.

De volledige broncode van dit artikel is te vinden op GitHub.


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