Cechy ogórka: przegląd

Opublikowany: 2022-04-20

Wprowadzenie

Gherkin to język nadal używany w wielu frameworkach do automatyzacji testów. Czasami dzieje się tak dlatego, że klient wymaga od nas, abyśmy z niej korzystali, czasami dlatego, że zespół się na to zdecyduje.

Szczerze mówiąc, nie była to dla mnie miłość od pierwszego wejrzenia. Osobiście mam długą podróż z Korniszonem – od polubienia go na początku, przez chwilową niechęć do języka, a na końcu polubienia go ponownie. W tym artykule przedstawię najważniejsze cechy Cucumbera wraz z implementacją Javy.

Oto wszystkie funkcje ogórka omówione w tym artykule:

Funkcja Opis
Scenariusz Prosty scenariusz
Zarys scenariusza Wymaga od użytkownika podania danych testowych w sekcji „Przykłady”
Tabele danych Wymaga od użytkownika podania danych testowych dla etapu testowego
Kontekst scenariusza Udostępnianie wartości między etapami testu
Typy danych ogórka Typy danych obsługiwane przez ogórek
Ogórek Wyrażenie regularne Użycie wyrażenia regularnego w scenariuszach z ogórkiem
Haczyki na ogórki Wykonuje dodatkowy kod w scenariuszach testowych
Tabela 1. Funkcje ogórka i języka Java omówione w tym artykule

Plik funkcji

Przede wszystkim, czym jest plik funkcji? W świecie technicznym stworzono nietechniczne podejście, aby umożliwić osobom nietechnicznym współpracę z zespołem podczas tworzenia aplikacji. Język Gherkin powstał jako dodatkowa warstwa w podejściu BDD. Testy Gherkina znajdują się w tzw. plikach funkcji, które są sklejane kodem (Java, Kotlin, C# itp.). Zazwyczaj Gherkin jest bardzo łatwy w użyciu i wymaga minimalnej wiedzy programistycznej, ale są funkcje, które wymagają trochę kodowania.

Zacznijmy od czegoś prostego.

Scenariusz

Oto najbardziej podstawowy i najłatwiejszy w użyciu przykład testu na ogórek:

 Funkcja: Scenariusz

 Tło: przed scenariuszami testowymi
   Biorąc pod uwagę, że wykonuję przed krokiem

 @Test
 Scenariusz: Scenariusz 
   Biorąc pod uwagę, że używam sparametryzowanego kroku „Scenariusz 1”

Blok kodu 1. Scenariusz

Blok kodu 1. zawiera kilka rzeczy do wyjaśnienia:

  • Funkcja : tytuł pliku funkcji
  • Tło : słowo kluczowe, które umożliwia użytkownikowi wykonanie kroków testowych przed każdym scenariuszem testowym zdefiniowanym w pliku funkcji
  • @Test : Tag, który informuje platformę testową, jaki scenariusz testowy powinien zostać wykonany. „Test” jest definiowany przez użytkownika. Możemy użyć np. „@SmokeTest”
  • Scenariusz : Nazwa scenariusza testowego

Testy korniszonów używają słów kluczowych [Given, When, Then, But] przed każdym etapem testu. W naszym jedynym kroku testowym, z wyjątkiem kroku Background, używamy parametru, w którym przekazujemy wartość „Scenario 1”.

Zobaczmy teraz, jak wygląda sklejony kod Javy:

 @Given("Wykonuję przed krokiem")
public void iExecuteBeforeStep() {
   //jaka implementacja
}

@Given("Używam sparametryzowanego kroku {string}")
public void iUseParametrizedStepOf(String p) {
   //jaka implementacja
}

Blok kodu 2. Implementacja kodu Java scenariusza

Zarys scenariusza

Zróbmy coś bardziej złożonego:

 Funkcja: Zarys scenariusza

 @Test
 Zarys scenariusza: Zarys scenariusza
   Biorąc pod uwagę, że uruchamiam krok z „<parametr1>” i „<parametr2>”
 Przykłady:
     | parametr1 | parametr2 |
     | parametr1a | parametr2a |
     | parametr1b | parametr2b |

Blok kodu 3. Zarys scenariusza

Tym razem użyjemy Zarysu Scenariusza, który pozwoli nam powtórzyć scenariusze testowe z różnymi konfiguracjami danych testowych. Code Block 3. zawiera kilka rzeczy do wyjaśnienia:

  • Przykłady : macierz danych testowych do wykorzystania w scenariuszach testowych. Pierwszy wiersz to nagłówek z nazwami parametrów.

Oraz implementacja javy:

 @Given("Uruchamiam krok za pomocą {ciąg} i {ciąg}")
public void iRunStepWithAnd(String p1, String p2) {
   //jaka implementacja
}

Blok kodu 4. Implementacja Java scenariusza zarysu

Tabela danych

Zarys scenariusza jest bardzo przydatny, ale co, jeśli nie chcemy powtarzać całego scenariusza testowego, a tylko jeden krok testowy? Korniszon ma na to sposób i nazywa się „Tabelą danych”.

 Funkcja: Tabela danych

@Test
Scenariusz: Scenariusz tabeli danych
 Biorąc pod uwagę, że sprawdzam, czy kolumna zawiera oczekiwaną wartość
 | NazwaKolumny | oczekiwana wartość |
 | jakaśNazwaKolumny | jakaś oczekiwana wartość |

Blok kodu 5. Tabela danych

Scenariusz z Tabelą Danych nie różni się zbytnio od Zarysu Scenariusza. Jedyną rzeczą jest to, że przed tabelą nie umieszczamy słowa kluczowego „Przykłady”.

Implementacja Javy wygląda nieco bardziej skomplikowanie niż w poprzednich przypadkach:

 @Given("Sprawdzam, czy kolumna zawiera oczekiwaną wartość")
public void iVerifyColumnValuesInTableUsingQueryFromFileOnSchema(DataTable dataTable) {
   List<Map<String, String>> data = dataTable.asMaps();
   for (Map<String, String> form : data) {
       String nazwakolumny = form.get("nazwakolumny");
       String oczekiwaneResult = form.get("oczekiwanaWartość");
       //jaka implementacja
       }
   }
}

Blok kodu 6. Implementacja Java Tabeli danych

Aby uzyskać dostęp do danych z tabeli danych, tworzymy specjalną zmienną dataTable typu „DataTable”. Wszystkie dane będą przechowywane w zmiennej List.

Kontekst scenariusza

Korzystając z kontekstu scenariusza możemy udostępniać dane między krokami. Załóżmy, że mamy scenariusz dwuetapowy, w którym chcemy przekazać „dane” wartości z kroku 1 do kroku 2 (blok kodu 7).

 @Test
Scenariusz: kontekst scenariusza
 Biorąc pod uwagę, że ustawiłem wartość kontekstu scenariusza „dane”
 Biorąc pod uwagę, że używam wartości kontekstu scenariusza

Blok kodu 7. Kontekst scenariusza

Najpierw musimy zbudować specjalną klasę o nazwie ScenarioContext z funkcjami kontekstu scenariusza ustawiania i pobierania danych (blok kodu 8). Nasz kontekst scenariusza to HashMap z parą klucz-wartość. Będziemy identyfikować wartości po jego kluczu.

  • scenariuszContext() : HashMap pary klucz-wartość
  • setContext() : metoda klucz-wartość do przechowywania danych kontekstowych scenariusza
  • getContext() : metoda pobierania danych dostarczających klucz
 klasa publiczna ScenarioContext {

   private Map<String, Object> sceneContext;

   scenariusz publicznyContext(){
       scenariuszContext = new HashMap<>();
   }

   public void setContext(klucz kontekstowy, wartość obiektu) {
       scenariuszContext.put(klucz.toString(), wartość);
   }

   obiekt publiczny getContext(klucz kontekstowy){
       zwróć scenariuszContext.get(key.toString());
   }

}

Kontekst wyliczenia publicznego {
   ID;
}

Blok kodu 8. Implementacja Java klasy Scenario Context

Mając to możemy skorzystać z zaimplementowanych metod. W kroku 1 ustawiamy następnie wartość w kontekście scenariusza, aw kroku 2 otrzymujemy wartość (blok kodu 9).

 ScenarioContext scenariuszContext = nowy ScenarioContext();

@Given("Ustawiam wartość kontekstu scenariusza {string}")
public void iSetScenarioContextValue (wartość ciągu) {
   scenariuszContext.setContext(Context.ID, wartość);
}

@Given("Używam wartości kontekstu scenariusza")
public void iUseScenarioContextValue() {
   String sharedValue = scriptContext.getContext(Context.ID).toString();
}

Blok kodu 9. Kroki kontekstu scenariusza

Typy danych ogórka

Ogórek obsługuje ograniczoną liczbę typów danych. Możemy zdefiniować łańcuchy, liczby całkowite i wartości zmiennoprzecinkowe, ale w przypadku wartości logicznych musimy zakodować pewne obejścia.

 @Test
Scenariusz: Scenariusz ze zmiennymi
 Biorąc pod uwagę, że używam string "string", int 1, float 1.1 i boolean "false"

Blok kodu 10. Typy danych ogórka

Kod Javy wyglądałby mniej więcej tak:

 @Given("Używam string {string}, int {int}, float {float} i boolean {string}")
public void iUseStringIntFloatAndBoolean(String var1, int var2, double var3, String var4) {
   boolean f = Boolean.valueOf(var4);
   //jakiś kod
}

Blok kodu 11. Implementacja Java typów danych Cucumber

Ogórek Wyrażenie regularne

To kolejna często używana funkcja. Blok kodu 12 przedstawia dwuetapowy scenariusz, który różni się tylko przy użyciu różnych wartości zmiennych (var1 i var2). W rzeczywistości jest to tylko jeden krok, a w kodzie Java (Code Block 13) definiujemy tylko jedną metodę, ale z regexem i jednym parametrem var.

 @Test
Scenariusz: Scenariusz z wyrażeniem regularnym
 Biorąc pod uwagę, że używam zmiennej var1
 Biorąc pod uwagę, że używam zmiennej var2

Blok kodu 12. Wyrażenie regularne w ogórku

 @Given("^Używam zmiennej (.*)")
public void egzaminTabela CzasuWSlecie(String var) {
   if (zmienna.equals("zmienna1")){
       //jakiś kod
   }
   else if(var.equals("var2")){
       //jakiś kod
   }
}

Blok kodu 13. Implementacja w Javie wyrażenia regularnego Cucumber

Haczyki ogórkowe

Last but not least: haczyki ogórkowe.

Blok kodu 14 przedstawia 4 najważniejsze haki:

  • @Before : Wykonuje kod przed każdym scenariuszem testowym
  • @Po : Wykonuje kod po każdym scenariuszu testowym
  • @BeforeStep : Wykonuje kod przed każdym krokiem testowym
  • @AfterStep : Wykonuje kod po każdym kroku testowym
 @Zanim
public void beforeScenariusz() {
   //jakiś kod
}

@Później
public void afterScenario() {
   //jakiś kod
}

@Bez tytułu
public void beforestep() {
   //jakiś kod
}

@Poradnik
public void afterStep() {
   //jakiś kod
}

Blok kodu 14. Haczyki ogórkowe

Streszczenie

Mam nadzieję, że przekonałem Cię do wykorzystania Korniszona w swoich testach. Te kilka funkcji sprawi, że Twoje testy będą bardziej czytelne i łatwiejsze do zrozumienia przez osoby nietechniczne. Również nowym osobom łatwiej będzie zrozumieć logikę biznesową i skrócić ich czas na onboarding.