Cucumber-js: Wie kann ich eine Schrittdefinitionsdatei für jede Feature-Datei angeben?

Erstellt am 2. Feb. 2017  ·  18Kommentare  ·  Quelle: cucumber/cucumber-js

Mein Ziel

Ich versuche, eine skalierbare Struktur von Funktionen und Schrittdefinitionen für eine große Anwendung zu erstellen, und mein erster Versuch bestand darin, step_definition-Dateien mit Funktionen zu verknüpfen, damit ich dasselbe Schrittmuster für verschiedene Schrittdefinitionen verwenden kann.

Mein Code

Ich zeige mein aktuelles Beispiel:

Meine Ordnerstruktur:

/features/sample.feature
/features/example.feature
/features/step_definitions/sample_steps.js
/features/step_definitions/example_steps.js
/features/step_definitions/common/common_steps.js

In meinem sample.feature habe ich:

  Scenario: Launching Cucumber
  Given I have some step definitions
   When I check some step definition with parameter "any"
   Then I should see all green "sample"

In meinem example.feature habe ich:

  Scenario: Launching Cucumber
  Given I have some step definitions
   When I check some step definition with parameter "any"
   Then I should see all green "example"

Die Schritte Given und When sind in der Datei /common/common_steps.js definiert und funktionieren einwandfrei.

Der Schritt Then ist sowohl für sample_steps.js als auch example_steps.js definiert, jedoch unterschiedlich.

In meiner sample_steps.js habe ich:

Then('I should see all green {stringInDoubleQuotes}', (arg) => {
   if (arg !== 'sample') {
     throw 'I should see all green when the argument is "sample"';
   }
   return;
 });

Und schließlich habe ich in meiner example_steps.js:

Then('I should see all green {stringInDoubleQuotes}', (arg) => {
   if (arg !== 'example') {
     throw 'I should see all green when the argument is "example"';
   }
   return;
 });

Der Fehler

Mein Hauptziel ist es, hier alles grün zu haben, aber natürlich funktioniert es nicht und ich bekomme diesen offensichtlichen Fehler:

Multiple step definitions match:
   I should see all green {stringInDoubleQuotes} - features\step_definitions\example_steps.js:6
   I should see all green {stringInDoubleQuotes} - features\step_definitions\sample_steps.js:6

Gurken-JVM

Ich weiß, dass wir in cucumber-jvm ein glue -Attribut angeben können, das Features und step_definitions verknüpft, und es ist genau das, wonach ich suche, aber in cucumber-js. Beispiel in Java:

@RunWith(Cucumber.class)
@Cucumber.Options( glue = { "com.app.stepdefinitions.common", "com.app.stepdefinitions.sample" } )
public class SampleFeature{
}

@RunWith(Cucumber.class)
@Cucumber.Options( glue = { "com.app.stepdefinitions.common", "com.app.stepdefinitions.example" } )
public class ExampleFeature{
}

Endlich

Wie kann ich mit cucumber-js dasselbe erreichen wie cucumbr-jvm?

Hilfreichster Kommentar

IMO Scoping ist definitiv erforderlich. Wenn Ihre Anwendung wächst, erweitert sich die Anzahl der Funktionen und Sie werden am Ende widersprüchliche Beschreibungen in verschiedenen Kontexten erhalten.

In meinem Unternehmen hat unser Produkt Hunderte von Funktionen und QA hat Testfälle im Bereich von 100.000.
Wenn wir cucumber verwenden, werden wir definitiv auf dieses Problem stoßen.

Ja, ich denke, Sie sollten den Kontext berücksichtigen, anstatt den Umfang zu berücksichtigen.
Sie können die meisten, wenn nicht alle Ihrer Schrittdefinitionen im Standardkontext (oder ohne Kontext) haben, aber es sollte eine Möglichkeit geben, den Kontext anzugeben, ohne dass eine benutzerdefinierte DSL erforderlich ist.

Es sind BA und QA, die diese Tests schreiben sollten, und jede benutzerdefinierte DSL wird zwangsläufig Verwirrung und Widerstand hervorrufen.

Das Feature/Szenario stellt per Definition bereits Kontexte bereit, deshalb hat die Gherkin-Syntax die Einrückung.

Das Hinzufügen von Tags und benutzerdefiniertem DSL ist eine Problemumgehung der Implementierungsbeschränkung (dh ein Hack, IMO) anstelle einer Lösung.

Vielleicht können Sie dies berücksichtigen, während Sie https://github.com/cucumber/cucumber-js/issues/745 berücksichtigen?

Wie wäre es, Scenario von defineStep zu erweitern und {Given, When, Then} in den Rückruf zu übergeben?

dh:

import {defineSupportCode} from 'cucumber'

defineSupportCode(({ Scenario, Given, When, Then }) => {
  Given(...)
  When(...)
  Then(...)
  Scenario('<match scenario description>', ({ Given, When, Then}) => {
    Given('<take precedent of non-contexted>', ...)
    ...
  })
})

Alle 18 Kommentare

Ich versuche, eine skalierbare Struktur von Funktionen und Schrittdefinitionen für eine große Anwendung zu erstellen, und mein erster Versuch bestand darin, step_definition-Dateien mit Funktionen zu verknüpfen, damit ich dasselbe Schrittmuster für verschiedene Schrittdefinitionen verwenden kann.

Sehr interessant. cucumber-js hat nichts eingebautes wie das cucumber-java-Beispiel, das Sie gegeben haben. Die Idee, die ich für diese Art von Dingen mag, besteht darin, diese Logikumschaltung in Ihr Welt-Setup oder Ihre Instanz zu schieben. In beiden Fällen erhalten Sie nur eine Schrittdefinition. Sie können mehrere World-Definitionen haben, zwischen denen Sie wechseln, wenn Sie Ihren Support-Code definieren, oder Sie haben eine einzelne World-Instanz, die je nach Kontext verschiedene Methoden verfügbar macht. Wir machen die Datei des aktuellen Szenarios derzeit nicht für laufende Schritte verfügbar, aber Sie können Tags verwenden, um Ihren Kontext zu bestimmen.

Wir haben eigentlich den gleichen Bedarf dafür. Wir verwenden Nightwatch-Cucumber , um Selentests durchzuführen, und unsere einzige Lösung besteht im Moment darin, jedem Schritt ein Präfix hinzuzufügen:

Given [comp1] I click on "Open dialog"

vs

Given [comp2] I click on "Open dialog"

Dies hilft uns, mehrdeutige Schrittdefinitionen zu vermeiden, führt aber zu wirklich unlesbaren Feature-Dateien.
Ich habe versucht, an der cucumber.js-Quelle herumzubasteln, aber keine guten Hinweise gefunden, um Unterstützung für diese Funktion hinzuzufügen.

Könnte man das mit ein paar Hooks oder Alternativwelten realisieren?

@leipert welche Benutzeroberfläche stellst du dir vor? Ich glaube, diese Logik sollte in der Welt leben oder mehrere Weltobjekte unterstützen. Dann befassen sich die Schrittdefinitionen nur damit, die Gherkin-Übereinstimmungen zu analysieren und sie an die richtige Weltfunktion zu übergeben. Wir könnten eine CLI-Option hinzufügen, um auszuwählen, welches Weltobjekt verwendet werden soll.

Wenn Sie im Moment mehrere Welten/Schrittdefinitionen haben möchten, können Sie dies erreichen, indem Sie Ihren Code in separaten Ordnern ablegen und nur einen davon pro Ausführung benötigen (mithilfe der CLI-Option --require).

Nun, "das Gurkenbuch" rät ausdrücklich von dieser Art der Gestaltung von Schritten ab. Step wird von Szenario zu Design geteilt, derselbe Satz sollte trotz der Funktion, die ihn verwendet, eine konsistente Bedeutung haben. Sobald Sie den Umfang der Schritte eingeführt haben, ist es wirklich einfach, eine Sprachfalle zu erstellen.

Bisher kommen nur Tags in cucuber.js Ihrem Zweck nahe. Aber nur Hooks können erklären, dass sie spezifisch für Tags sind. Wenn Sie sicher sind, dass es der richtige Weg für Ihre Leute ist, können Sie eine DSL erfinden, vielleicht einfach als [Funktionsname] im Schrittmuster.

Danke, @pinxue . Sehr nützliche Antwort. Allerdings kann ich es nicht nachvollziehen:

Nun, "das Gurkenbuch" rät ausdrücklich von dieser Art der Gestaltung von Schritten ab.

Ein und derselbe Aktionssatz kann in verschiedenen Kontexten unterschiedliche Bedeutungen haben. Aber es ist ok. Es ist gut zu wissen, welche Optionen ich habe. Eigentlich gehen wir bereits über eine interne DSL, um dies zu erreichen.

Vielen Dank.

Danke für deine Antworten @pinxue und @robsonrosa.
Hier ist meine Begründung für bereichsbezogene Schrittdefinitionen:

  1. _Globale Variablen sind schlecht und skalieren nicht_:
    Wir haben nur etwa 15 Feature-Dateien mit jeweils 10 Szenarien, und es ist schon schwierig, alle Schrittdefinitionen und Feature-Dateien zu strukturieren. Für große Anwendungen (z. B. 100 Feature-Dateien mit 10 Szenarien mit durchschnittlich 5 Schritten) erscheint es verrückt, alle Schritte global definiert zu haben, da es wirklich schwierig ist, nachzuverfolgen, welche Feature-Datei welche Schritte verwendet.
  2. _Entwickler haben keine Kontrolle über den Wortlaut in Feature-Dateien_:
    In unserem Anwendungsfall schreibt unser "Management" Feature-Dateien, es ist schwer, sie zu verkaufen: Wir machen großartiges BDD, aber Sie müssen sich auf eine umständliche benutzerdefinierte DSL beschränken.
  3. _Wenn cucumber-jvm die Option hat, warum nicht cucumber-js ?_
    Das ist vielleicht ein schlechtes Argument 💃

Ich sehe folgende Ansätze, um das Problem für uns zu lösen:

  1. Erstellen Sie eine benutzerdefinierte DSL mit Präfixen in Schrittdefinitionen
    Nachteile: Nicht schön damit zu arbeiten.
    Vorteile: Keine Änderungen in cucumber.js erforderlich
  2. Erstellen Sie glue für cucumber.js
    Nachteile: Kann gegen die Idee von "The Cucumber Book" verstoßen.
    Vorteile: Feature-Parität mit cucumber.js
  3. Ändern Sie, wie wir die Tests durchführen
    Nachteile: Diese Funktion wird weniger Personen zur Verfügung stehen.
    Vorteile: Keine Änderungen in cucumber.js erforderlich

Davon abgesehen werden wir uns wahrscheinlich für 3. entscheiden, wenn die Betreuer von cucumber.js der Meinung sind, dass bereichsbezogene Schrittdefinitionen für dieses Projekt außerhalb des Bereichs liegen (Wortspiel beabsichtigt).

@robsonrosa Mich würde deine Lösung interessieren, sobald du eine hast.

IMO Scoping ist definitiv erforderlich. Wenn Ihre Anwendung wächst, erweitert sich die Anzahl der Funktionen und Sie werden am Ende widersprüchliche Beschreibungen in verschiedenen Kontexten erhalten.

In meinem Unternehmen hat unser Produkt Hunderte von Funktionen und QA hat Testfälle im Bereich von 100.000.
Wenn wir cucumber verwenden, werden wir definitiv auf dieses Problem stoßen.

Ja, ich denke, Sie sollten den Kontext berücksichtigen, anstatt den Umfang zu berücksichtigen.
Sie können die meisten, wenn nicht alle Ihrer Schrittdefinitionen im Standardkontext (oder ohne Kontext) haben, aber es sollte eine Möglichkeit geben, den Kontext anzugeben, ohne dass eine benutzerdefinierte DSL erforderlich ist.

Es sind BA und QA, die diese Tests schreiben sollten, und jede benutzerdefinierte DSL wird zwangsläufig Verwirrung und Widerstand hervorrufen.

Das Feature/Szenario stellt per Definition bereits Kontexte bereit, deshalb hat die Gherkin-Syntax die Einrückung.

Das Hinzufügen von Tags und benutzerdefiniertem DSL ist eine Problemumgehung der Implementierungsbeschränkung (dh ein Hack, IMO) anstelle einer Lösung.

Vielleicht können Sie dies berücksichtigen, während Sie https://github.com/cucumber/cucumber-js/issues/745 berücksichtigen?

Wie wäre es, Scenario von defineStep zu erweitern und {Given, When, Then} in den Rückruf zu übergeben?

dh:

import {defineSupportCode} from 'cucumber'

defineSupportCode(({ Scenario, Given, When, Then }) => {
  Given(...)
  When(...)
  Then(...)
  Scenario('<match scenario description>', ({ Given, When, Then}) => {
    Given('<take precedent of non-contexted>', ...)
    ...
  })
})

Ich lerne BDD von http://fitnesse.org/ , also sehe ich BDD vielleicht anders als in der Gurken-Community.

Paging @richardlawrence

Dies ist ein Bereich, in dem Cucumber besonders eigensinnig ist. Es basiert auf der Überzeugung, dass Teams eine allgegenwärtige Sprache entwickeln sollten, in der Wörter und Ausdrücke im Kontext einer Anwendung genau eine Sache bedeuten und konsistent verwendet werden. Global Schritt zu halten, hält einen positiven Druck aufrecht, um Mehrdeutigkeiten zu vermeiden.

In den seltenen Fällen, in denen eine Anwendung mehrere unterschiedliche begrenzte Kontexte (in DDD-Begriffen) hat, würden Sie Ihre Cucumber-Suite einfach entlang der gleichen Linien aufteilen, wie Ihre Anwendung aufgeteilt ist, um diese Grenze widerzuspiegeln, und Schrittdefinitionen wären innerhalb jedes begrenzten Kontexts global.

Ein Artikel über die Arbeit mit Cucumber und das Erstellen von Grenzen. Es implementiert einige der Ideen auf dieser Seite, bietet aber keine großartigen Lösungen, da @richardlawrence erwähnt hat, dass Sie Cucumber nicht so konfigurieren können, dass es sich auf eine bestimmte Klasse für Schrittdefinitionen konzentriert. http://confessionsofanagilecoach.blogspot.com/2017/05/teaching-cucumbers-about-boundaries.html

Wie @leipert sagte, sind globale Variablen schlecht. Ich denke, diejenigen von uns in der CucumberJVM-Welt bekommen nur die halbe Wahrheit. Cucumber (nicht JVM) verwendet ein ordentliches Weltkonzept, das einen globalen Speicherplatz für die Dauer des Szenarios darstellt. Nachdem das Szenario ausgeführt wurde, wird es zerstört. Das fühlt sich nach einer guten Lösung an. Aber ... Ich habe keine gute Implementierung dieses Musters in CucumberJVM gesehen. Wenn Cucumber uns also zwingt, einen flachen/globalen Namensraum für Schrittdefinitionen zu haben, und CucumberJVM ein klares Entwurfsmuster für die Implementierung des Weltmusters hatte, dann bin ich etwas glücklicher. Bis zu diesem Punkt CucumberJVM + World pattern == übermäßig komplizierte Lösungen. Bisher war alles, was ich gesehen habe, komplizierter, als mich einfach kontrollieren zu lassen, welche Schrittfunktionen zu welcher Feature-Datei gehören. Die Alternativen, die ich bisher gesehen habe, geben mir bei all dem Aufwand/Aufwand nichts Wertvolleres. Andere Gurkensorten haben bessere Weltlösungen.

Letztendlich bin ich selbst mit dem Weltmuster immer noch unzufrieden, weil ich weiß, dass es zu Informationsverlusten kommt, wenn ich von der Feature-Datei zu den Schritten gehe. Wenn ich mich sehr anstrenge: meine Feature-Dateien in eine gute Organisation zu bringen, gute Feature-Dateinamen zu erstellen, mein Feature auf intelligente Weise zu deklarieren, meine Szenarien auf intelligente Weise zu benennen – wird der gesamte Kontext aus dem Fenster geworfen und ich bin gezwungen um mit dem globalen Schrittdefinitionsnamensraum zu arbeiten.

Ich kann nur daran denken, die Beziehung aus den Validierungen des Systems herauszuhalten und einfach Platzhalter in den Pfaden für die Tests hinzuzufügen und sie zum Laufen zu bringen, selbst wenn dafür ein Open-Source-Framework geändert werden muss. könnte es versuchen, wenn unser Projekt wächst.

Ich verstehe Ihr Ziel, aber ich würde es nicht empfehlen.
Ich würde auch empfehlen, explizite .feature-Dateien zu haben, entweder mit einer Hintergrundanweisung oder einem zusätzlichen gegebenen Schritt, der dies explizit macht.

Alternativ könnten Sie zwei verschiedene Konfigurationsdateien erstellen.
Eine für die Probe und eine für das Beispiel.
Dann könnten Sie auf verschiedene Schrittordner verweisen.

@robsonrosa @leipert Ich teile deine Meinung
Fast zwei Jahre nach dem ursprünglichen Post...
Hast du damit Fortschritte gemacht? Irgendeine Problemumgehung?

@cristianmercado19 Entschuldigung, nein. Ich verwende Gurken-js nicht mehr.

Ups ... Ich mag die Art und Weise, Feature-Dateien zu schreiben, die vollständig von der Implementierung des Schritts isoliert sind.
Ich habe versucht, das gleiche Ziel mit _mocha_ zu erreichen, aber ich bin nicht zufrieden damit.
Wenn Sie eine andere Alternative haben, die meinem Ziel entspricht, versuchen Sie es gerne.
Vielen Dank für Ihre Hilfe @leipert .

Dieser Thread wurde automatisch gesperrt, da es nach seiner Schließung keine Aktivitäten mehr gegeben hat. Bitte öffnen Sie ein neues Problem für verwandte Fehler.

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen