Agurkdatatabeller

1. Introduktion

Agurk er en Behavioral Driven Development (BDD) ramme, der giver udviklere mulighed for at oprette tekstbaserede testscenarier ved hjælp af Gherkin-sproget. I mange tilfælde kræver disse scenarier mock-data for at udøve en funktion, som kan være besværlig at injicere - især med komplekse eller flere poster.

I denne vejledning ser vi på, hvordan man bruger agurkdatatabeller til at inkludere mock-data på en læsbar måde.

2. Scenario-syntaks

Når vi definerer agurkscenarier, indsprøjter vi ofte testdata, der bruges af resten af ​​scenariet:

Scenarie: Korrekt antal bøger, der ikke er nul, fundet af forfatter Da jeg har en bog i butikken, der hedder Djævelen i den hvide by af Erik Larson Når jeg søger efter bøger af forfatter Erik Larson Så finder jeg 1 bog

2.1. Datatabeller

Mens integrerede data er tilstrækkelige for en enkelt bog, kan vores scenario blive rodet, når der tilføjes flere bøger. For at håndtere dette opretter vi en datatabel i vores scenario:

Scenarie: Korrekt antal bøger, der ikke er nul, fundet af forfatteren Da jeg har følgende bøger i butikken | Djævelen i den hvide by | Erik Larson | | Løven, heksen og klædeskabet | C.S. Lewis | | I Dyrenes Have | Erik Larson | Når jeg søger efter bøger af forfatter Erik Larson, finder jeg 2 bøger

Vi definerer vores datatabel som en del af vores Givet klausul af indrykning af bordet under teksten i Givet klausul. Ved hjælp af denne datatabel kan vi tilføje et vilkårligt antal bøger - inklusive kun en enkelt bog - til vores butik ved at tilføje eller fjerne rækker.

Derudover datatabeller kan bruges med en hvilken som helst klausul - ikke kun Givet klausuler.

2.2. Herunder overskrifter

Det er tydeligt, at den første søjle repræsenterer titlen på bogen, og den anden søjle repræsenterer forfatteren af ​​bogen. Betydningen af ​​hver kolonne er dog ikke altid så indlysende.

Når der er behov for afklaring, Vi kan inkludere en header ved at tilføje en ny første række:

Scenarie: Korrekt antal bøger, der ikke er nul, fundet af forfatteren Da jeg har følgende bøger i butikken | titel | forfatter | | Djævelen i den hvide by | Erik Larson | | Løven, heksen og klædeskabet | C.S. Lewis | | I Dyrenes Have | Erik Larson | Når jeg søger efter bøger af forfatter Erik Larson, finder jeg 2 bøger

Mens overskriften ser ud til at være en ny række i tabellen, denne første række har en særlig betydning når vi analyserer vores tabel i en liste over kort i det næste afsnit.

3. Trindefinitioner

Efter at have oprettet vores scenario implementerer vi Givet trindefinition. I tilfælde af et trin, der indeholder en datatabel, vi implementerer vores metoder med en Datatabel argument:

@Given ("nogle sætninger") offentlig annullerer somePhrase (tabellen DataTable) {// ...}

Det Datatabel objekt indeholder tabeldataene fra datatabellen, som vi definerede i vores scenario, såvel som metoder til at omdanne disse data til brugbar information. Generelt er der tre måder at transformere en datatabel i Agurk på: (1) en liste med lister, (2) en liste over kort og (3) en bordtransformator.

For at demonstrere hver teknik bruger vi en simpel Bestil domæne klasse:

public class Book {privat strengetitel; privat strengforfatter; // standardkonstruktører, getters & settere ...}

Derudover opretter vi en Boghandel klasse, der administrerer Bestil genstande:

public class BookStore {private List books = new ArrayList (); public void addBook (Bogbog) {books.add (bog); } public void addAllBooks (Collection books) {this.books.addAll (books); } public List booksByAuthor (String author) {return books.stream () .filter (book -> Objects.equals (author, book.getAuthor ())) .collect (Collectors.toList ()); }}

For hvert af de følgende scenarier starter vi med en grundlæggende trindefinition:

offentlig klasse BookStoreRunSteps {privat BookStore-butik; privat liste fundet Bøger; @Før offentlig ugyldig setUp () {butik = ny BookStore (); foundBooks = ny ArrayList (); } // Hvornår og derefter definitioner ...}

3.1. Liste over lister

Den mest basale metode til håndtering af tabeldata er konvertering af Datatabel argument i en liste over lister. Vi kan oprette en tabel uden et overskrift for at demonstrere:

Scenarie: Korrekt antal bøger, der ikke er nul, fundet af forfatter efter liste Da jeg har følgende bøger i butikken efter liste | Djævelen i den hvide by | Erik Larson | | Løven, heksen og klædeskabet | C.S. Lewis | | I Dyrenes Have | Erik Larson | Når jeg søger efter bøger af forfatter Erik Larson, finder jeg 2 bøger

Agurk konverterer ovenstående tabel til en liste over lister ved at behandle hver række som en liste over kolonneværdierne. Således analyserer agurk hver række i en liste, der indeholder bogtitlen som det første element og forfatteren som den anden:

[["Djævelen i den hvide by", "Erik Larson"], ["Løven, heksen og klædeskabet", "C.S. Lewis"], ["I dyrenes have", "Erik Larson"]]

Vi bruger asLister metode - leverer en Streng.klasse argument - at konvertere Datatabel argument til en Liste. Det her Klasse argumentet informerer asLister metode hvilken datatype vi forventer at hvert element skal være. I vores tilfælde ønsker vi, at titlen og forfatteren skal være Snor værdier. Således leverer vi Streng.klasse:

@Given ("^ Jeg har følgende bøger i butikken efter liste $") public void haveBooksInTheStoreByList (DataTable table) {List rækker = tabel.asLister (String.class); for (Listekolonner: rækker) {store.addBook (ny bog (columns.get (0), columns.get (1))); }}

Vi gentager derefter hvert element på underlisten og opretter et tilsvarende Bestil objekt. Endelig tilføjer vi hver oprettet Bestil modsætter sig vores Boghandel objekt.

Hvis vi parsede data, der indeholder en overskrift, vi springer over den første række da agurk ikke skelner mellem overskrifter og række data for en liste over lister.

3.2. Liste over kort

Mens en liste over lister giver en grundlæggende mekanisme til udpakning af elementer fra en datatabel, kan trinimplementeringen være kryptisk. Agurk giver en liste over kortmekanismer som et mere læsbart alternativ.

I dette tilfælde, vi skal give en overskrift til vores bord:

Scenarie: Korrekt antal bøger, der ikke er nul, fundet af forfatteren efter kort Da jeg har følgende bøger i butikken efter kort | titel | forfatter | | Djævelen i den hvide by | Erik Larson | | Løven, heksen og klædeskabet | C.S. Lewis | | I Dyrenes Have | Erik Larson | Når jeg søger efter bøger af forfatter Erik Larson, finder jeg 2 bøger

Svarende til listen over lister mekanisme opretter agurk en liste, der indeholder hver række, men i stedet kortlægger kolonneoverskriften til hver kolonneværdi. Agurk gentager denne proces for hver efterfølgende række:

[{"title": "Djævelen i den hvide by", "author": "Erik Larson"}, {"title": "The Lion, the Witch and the Wardrobe", "author": "CS Lewis"} , {"title": "I dyrenes have", "author": "Erik Larson"}]

Vi bruger asMaps metode - leverer to Streng.klasse argumenter - at konvertere Datatabel argument til en Liste. Det første argument angiver datatypen for nøglen (header), og det andet angiver datatypen for hver kolonneværdi. Således leverer vi to Streng.klasse argumenter, fordi vores overskrifter (nøgle) og titel og forfatter (værdier) alle er Snors.

Så gentager vi hver Kort objekt og udtræk hver kolonneværdi ved hjælp af kolonneoverskriften som nøgle:

@Given ("^ Jeg har følgende bøger i butikken ved kort $") public void haveBooksInTheStoreByMap (DataTable table) {List rækker = tabel.asMaps (String.class, String.class); for (Kortkolonner: rækker) {store.addBook (ny bog (kolonner.get ("titel"), kolonner.get ("forfatter"))); }}

3.3. Bordtransformator

Den sidste (og mest rige) mekanisme til at konvertere datatabeller til brugbare objekter er at oprette en TableTransformer. EN TableTransformer er et objekt, der instruerer agurk, hvordan man konverterer en Datatabel modsætter sig det ønskede domæneobjekt:

Lad os se et eksempel på scenarie:

Scenarie: Korrekt antal bøger, der ikke er nul, fundet af forfatter med transformer Da jeg har følgende bøger i butikken med transformer | titel | forfatter | | Djævelen i den hvide by | Erik Larson | | Løven, heksen og klædeskabet | C.S. Lewis | | I Dyrenes Have | Erik Larson | Når jeg søger efter bøger af forfatter Erik Larson, finder jeg 2 bøger

Mens en liste over kort med dets nøgleordede søjledata er mere præcis end en liste med lister, rydder vi stadig vores trindefinition med konverteringslogik. I stedet, vi skal definere vores trin med det ønskede domæneobjekt (i dette tilfælde en Bogkatalog) som argument:

@Given ("^ Jeg har følgende bøger i butikken med transformer $") public void haveBooksInTheStoreByTransformer (BookCatalog katalog) {store.addAllBooks (catalog.getBooks ()); }

At gøre dette, vi skal oprette en brugerdefineret implementering af TypeRegistryConfigurer interface.

Denne implementering skal udføre to ting:

  1. Opret en ny TableTransformer implementering.
  2. Registrer denne nye implementering ved hjælp af configureTypeRegistry metode.

At fange Datatabel i et brugbart domæneobjekt opretter vi et Bogkatalog klasse:

public class BookCatalog {private List books = new ArrayList (); public void addBook (Bogbog) {books.add (bog); } // standard getter ...}

Lad os implementere for at udføre transformationen TypeRegistryConfigurer grænseflade:

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

og derefter implementere TableTransformer interface til vores Bogkatalog klasse:

 privat statisk klasse BookTableTransformer implementerer TableTransformer {@Override public BookCatalog transform (DataTable table) throw Throwable {BookCatalog catalog = new BookCatalog (); table.cells () .stream () .skip (1) // Spring over header række .map (felter -> ny bog (fields.get (0), fields.get (1))) .forEach (katalog :: addBook ); retur katalog; }}}

Bemærk, at vi transformerer engelske data fra tabellen, og derfor returnerer vi det engelske sprog fra vores landestandard () metode. Når vi analyserer data i et andet land, skal vi skift returtype for landestandard () metode til det relevante sted.

Da vi inkluderede en datatabeloverskrift i vores scenario, vi skal springe over den første række, når det gentages over bordcellerne (deraf spring (1) opkald). Vi fjerner spring (1) ring, hvis vores tabel ikke indeholdt en overskrift.

Som standard er limkode, der er knyttet til en test, antages at være i samme pakke som løberklassen. Derfor er der ikke behov for yderligere konfiguration, hvis vi inkluderer vores BookStoreRegistryConfigurer i samme pakke som vores løberklasse. Hvis vi tilføjer konfiguratoren i en anden pakke, vi skal eksplicit inkludere pakken i @CucumberOptionslim Mark til løberklassen.

4. Konklusion

I denne artikel har vi set på, hvordan man definerer et agurkescenario med data i tabelform ved hjælp af en datatabel. Derudover undersøgte vi tre måder at implementere en trindefinition, der bruger en agurktatatabel.

Mens en liste med lister og en liste over kort er tilstrækkelige til grundlæggende tabeller, giver en tabeltransformator en meget rigere mekanisme, der er i stand til at håndtere mere komplekse data.

Den komplette kildekode til denne artikel kan findes på GitHub.