Cucumber-js: Comment puis-je spécifier un fichier de définition d'étape pour chaque fichier de fonctionnalité ?

Créé le 2 févr. 2017  ·  18Commentaires  ·  Source: cucumber/cucumber-js

Mon but

J'essaie de créer une structure évolutive de fonctionnalités et de définitions d'étapes pour une grande application et mon premier coup a été d'essayer de lier les fichiers step_definition aux fonctionnalités afin que je puisse utiliser le même modèle d'étape pour différentes définitions d'étapes.

Mon code

Je montre mon exemple actuel:

Ma structure de dossier :

/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

Dans mon sample.feature j'ai :

  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"

Dans mon example.feature j'ai :

  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"

Les étapes Given et When sont définies dans le fichier /common/common_steps.js et fonctionnent correctement.

Le pas Then est défini à la fois pour sample_steps.js et example_steps.js mais différemment.

Dans mon sample_steps.js j'ai :

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

Et, enfin, dans mon example_steps.js j'ai :

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

L'erreur

Mon objectif principal est d'avoir tout vert ici, mais bien sûr, cela ne fonctionne pas et j'obtiens cette erreur évidente :

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

Concombre-JVM

Je sais que dans cucumber-jvm, nous pouvons spécifier un attribut glue qui relie les fonctionnalités et les step_definitions et c'est exactement ce que je recherche, mais dans cucumber-js. Exemple en 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{
}

finalement

Comment puis-je obtenir la même chose que cucumbr-jvm en utilisant cucumber-js ?

Commentaire le plus utile

La portée de l'OMI est absolument nécessaire. Au fur et à mesure que votre application grandit, le nombre de fonctionnalités augmente et vous vous retrouverez avec des descriptions contradictoires dans différents contextes.

Dans mon entreprise, notre produit a des centaines de fonctionnalités et QA a des cas de test dans la gamme 100k.
Si nous utilisons cucumber , nous rencontrerons certainement ce problème.

Oui, je pense que vous devriez considérer le contexte plutôt que la portée.
Vous pouvez avoir la plupart, sinon la totalité, de vos définitions d'étape dans le contexte par défaut (ou sans contexte), mais il devrait y avoir un moyen de spécifier le contexte sans avoir besoin d'un DSL personnalisé.

C'est le BA et le QA qui devraient écrire ces tests et tout DSL personnalisé est voué à créer de la confusion et de la résistance.

La fonction/le scénario fournit déjà des contextes par définition, c'est pourquoi la syntaxe Gherkin a l'indentation.

L'ajout de balises et de DSL personnalisés est une solution de contournement de la limitation de mise en œuvre (c'est-à-dire un hack, IMO) au lieu d'une solution.

Peut-être pouvez-vous considérer cela tout en considérant https://github.com/cucumber/cucumber-js/issues/745 ?

Que diriez-vous d'étendre Scenario partir de defineStep et de passer {Given, When, Then} dans le rappel ?

c'est à dire:

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>', ...)
    ...
  })
})

Tous les 18 commentaires

J'essaie de créer une structure évolutive de fonctionnalités et de définitions d'étapes pour une grande application et mon premier coup a été d'essayer de lier les fichiers step_definition aux fonctionnalités afin que je puisse utiliser le même modèle d'étape pour différentes définitions d'étapes.

Très intéressant. concombre-js n'a rien de intégré comme l'exemple concombre-java que vous avez donné. L'idée que j'aime pour ce genre de chose, c'est de pousser cette commutation logique dans votre configuration mondiale ou votre instance. Dans tous les cas, vous vous retrouvez avec une seule définition d'étape. Vous pouvez avoir plusieurs définitions de monde entre lesquelles vous basculez lors de la définition de votre code de support ou avoir une seule instance de monde qui expose différentes méthodes en fonction du contexte. Nous n'exposons pas actuellement le fichier du scénario actuel aux étapes en cours d'exécution, mais vous pouvez utiliser des balises pour déterminer votre contexte.

Nous avons en fait le même besoin pour cela. Nous utilisons nightwatch-cucumber pour exécuter des tests de sélénium et notre seule solution pour l'instant est d'ajouter un préfixe à chaque étape :

Given [comp1] I click on "Open dialog"

vs

Given [comp2] I click on "Open dialog"

Cela nous aide à éviter les définitions d'étape ambiguës, mais conduit à des fichiers de fonctionnalités vraiment illisibles.
J'ai essayé de bricoler avec la source cucumber.js, mais je n'ai trouvé aucun bon indice pour ajouter la prise en charge de cette fonctionnalité.

Cela pourrait-il être réalisé avec des crochets ou des mondes alternatifs ?

@leipert quelle interface utilisateur envisagez-vous ? Je crois que cette logique devrait vivre dans le monde ou prendre en charge plusieurs objets du monde. Ensuite, les définitions d'étape traitent simplement de l'analyse des correspondances de gherkin et de leur transmission à la fonction de monde appropriée. Nous pourrions ajouter une option CLI pour sélectionner l'objet du monde à utiliser.

Pour le moment, si vous souhaitez avoir plusieurs définitions de mondes / étapes, vous pouvez y parvenir en plaçant votre code dans des dossiers séparés et en n'en nécessitant qu'un par exécution (en utilisant l'option --require CLI).

Eh bien, "le livre du concombre" décourage spécifiquement cette façon de concevoir les étapes. L'étape est partagée entre les scénarios par conception, la même phrase doit avoir une signification cohérente malgré la fonctionnalité qui l'utilise. Une fois que vous avez introduit la portée des étapes, il est vraiment facile de créer un piège linguistique.

Jusqu'à présent, seules les balises sont proches de votre objectif dans cucuber.js. Mais seuls les crochets peuvent déclarer qu'ils sont spécifiques aux balises. Si vous êtes certain que c'est la bonne voie pour votre personnel, vous pouvez inventer un DSL, peut-être simple comme [nom de la fonctionnalité] dans le modèle d'étape.

Merci, @pinxue . Réponse très utile. Par contre je n'arrive pas à comprendre :

Eh bien, "le livre du concombre" décourage spécifiquement cette façon de concevoir les étapes.

Une même phrase d'action peut avoir différentes significations dans différents contextes. Mais c'est OK. C'est bon de connaître les options que j'ai, En fait, nous marchons déjà sur un DSL interne pour y parvenir,

Merci beaucoup.

Merci pour vos réponses @pinxue et @robsonrosa.
Voici mon raisonnement pour les définitions d'étapes étendues :

  1. _Les variables globales sont mauvaises et ne sont pas mises à l'échelle_ :
    Nous avons juste environ 15 fichiers de fichiers de fonctionnalités avec 10 scénarios chacun, et il est déjà difficile de structurer toutes les définitions d'étapes et les fichiers de fonctionnalités. Pour les grandes applications (disons 100 fichiers de fonctionnalités avec 10 scénarios avec une moyenne de 5 étapes), avoir toutes les étapes définies globalement semble insensé, car il est vraiment difficile de savoir quel fichier de fonctionnalités utilise quelles étapes.
  2. _Les développeurs n'ont aucun contrôle sur le libellé des fichiers de fonctionnalités_ :
    Dans notre cas d'utilisation, notre "gestion" écrit des fichiers de fonctionnalités, il est difficile de les vendre : nous faisons des BDD géniaux, mais vous devez vous limiter à un DSL personnalisé gênant.
  3. _Si cucumber-jvm a l'option, pourquoi pas cucumber-js ?_
    C'est peut-être un mauvais argument 💃

Je vois les approches suivantes pour résoudre le problème pour nous :

  1. Créer un DSL personnalisé avec des préfixes dans les définitions d'étape
    Inconvénients : Pas agréable à travailler.
    Avantages : ne nécessite aucun changement dans cucumber.js
  2. Créer glue pour concombre.js
    Inconvénients : Peut aller à l'encontre de l'idée de "The Cucumber Book".
    Avantages : Parité des fonctionnalités avec cucumber.js
  3. Changer la façon dont nous exécutons les tests
    Inconvénients : cette fonctionnalité sera disponible pour moins de personnes.
    Avantages : ne nécessite aucun changement dans cucumber.js

Cela étant dit, nous opterons probablement pour 3., si les responsables de cucumber.js pensent que les définitions d'étapes délimitées sont hors de portée (jeu de mots) pour ce projet.

@robsonrosa Je serais intéressé par votre solution, une fois que vous en aurez une.

La portée de l'OMI est absolument nécessaire. Au fur et à mesure que votre application grandit, le nombre de fonctionnalités augmente et vous vous retrouverez avec des descriptions contradictoires dans différents contextes.

Dans mon entreprise, notre produit a des centaines de fonctionnalités et QA a des cas de test dans la gamme 100k.
Si nous utilisons cucumber , nous rencontrerons certainement ce problème.

Oui, je pense que vous devriez considérer le contexte plutôt que la portée.
Vous pouvez avoir la plupart, sinon la totalité, de vos définitions d'étape dans le contexte par défaut (ou sans contexte), mais il devrait y avoir un moyen de spécifier le contexte sans avoir besoin d'un DSL personnalisé.

C'est le BA et le QA qui devraient écrire ces tests et tout DSL personnalisé est voué à créer de la confusion et de la résistance.

La fonction/le scénario fournit déjà des contextes par définition, c'est pourquoi la syntaxe Gherkin a l'indentation.

L'ajout de balises et de DSL personnalisés est une solution de contournement de la limitation de mise en œuvre (c'est-à-dire un hack, IMO) au lieu d'une solution.

Peut-être pouvez-vous considérer cela tout en considérant https://github.com/cucumber/cucumber-js/issues/745 ?

Que diriez-vous d'étendre Scenario partir de defineStep et de passer {Given, When, Then} dans le rappel ?

c'est à dire:

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>', ...)
    ...
  })
})

J'apprends le BDD sur http://fitnesse.org/ donc je peux regarder le BDD différemment de la communauté des concombres.

Radiomessagerie @richardlawrence

C'est un domaine où le concombre est particulièrement opiniâtre. Il est construit autour de la conviction que les équipes doivent développer un langage omniprésent, où les mots et les phrases signifient exactement une chose dans le contexte d'une application et sont utilisés de manière cohérente. Garder step defs global maintient une pression positive pour éviter toute ambiguïté.

Dans les rares cas où une application a plusieurs contextes délimités distincts (en termes DDD), vous diviseriez simplement votre suite Cucumber selon les mêmes lignes que votre application est divisée pour refléter cette limite, et les définitions d'étape seraient globales dans chaque contexte délimité.

Un article sur le travail avec Cucumber et la création de limites. Il implémente certaines des idées de cette page mais ne présente aucune solution intéressante car @richardlawrence a mentionné que vous ne pouvez pas configurer Cucumber pour qu'il se concentre sur une classe particulière pour les définitions d'étape. http://confessionsofanagilecoach.blogspot.com/2017/05/teaching-cucumbers-about-boundaries.html

Comme @leipert l' a dit, les variables globales sont mauvaises. Je pense que ceux d'entre nous dans le monde de CucumberJVM ne comprennent que la moitié de l'histoire. Cucumber (non JVM) utilise un concept de monde rangé qui est un espace mémoire global pour la durée du scénario . Une fois le scénario exécuté, il est détruit. Cela semble être une bonne solution. Mais... Je n'ai pas vu une bonne implémentation de ce modèle dans CucumberJVM. Donc, si Cucumber nous oblige à avoir un espace de noms plat/global pour les définitions d'étape, et que CucumberJVM avait un modèle de conception clair pour implémenter le modèle World, alors je suis un peu plus heureux. Jusqu'à présent, CucumberJVM + World pattern == solutions trop compliquées. Jusqu'à présent, tout ce que j'ai vu est plus compliqué que de simplement me laisser contrôler quelles fonctions d'étape vont avec quel fichier de fonctionnalité. Jusqu'à présent, les alternatives que j'ai vues ne me donnent rien de plus précieux pour tous les efforts/complexité. D'autres types de concombre ont de meilleures solutions mondiales.

En fin de compte, même avec le modèle World, je suis toujours mécontent car je sais qu'il y aura une perte d'informations lors du passage du fichier de fonctionnalités aux étapes. Si je fais beaucoup d'efforts : mettre mes fichiers de fonctionnalités dans une bonne organisation, créer de bons noms de fichiers de fonctionnalités, déclarer ma fonctionnalité de manière intelligente, nommer mes scénarios de manière intelligente - tout le contexte est jeté par la fenêtre et je suis forcé pour travailler avec l'espace de noms global de définition d'étape.

Je ne peux que penser à garder la relation hors des validations du système et simplement ajouter des caractères génériques sur les chemins pour les tests, et les faire fonctionner, même s'il faut modifier un framework open source. pourrait tenter sa chance au fur et à mesure que notre projet grandit.

Je comprends votre objectif, mais je ne le recommanderais pas.
Je recommanderais également d'avoir des fichiers .feature explicites, avec soit une déclaration d' arrière -plan, soit une étape donnée supplémentaire qui rend cela explicite.

Vous pouvez également créer deux fichiers de configuration différents.
Un pour l' échantillon et un autre pour l' exemple.
Ensuite, vous pouvez pointer vers différents dossiers d'étapes.

@robsonrosa @leipert je partage ton avis
Près de deux ans après le premier message...
Avez-vous fait des progrès avec ça? Une solution de contournement ?

@ cristianmercado19 Désolé, non. Je n'utilise plus concombre js.

Ups... J'aime la façon d'écrire un fichier de fonctionnalité complètement isolé de l'implémentation de l'étape.
J'ai essayé d'atteindre le même objectif avec _mocha_ mais je ne suis pas satisfait.
Si vous avez une autre alternative qui engage mon objectif, plus qu'heureux d'essayer.
Appréciez votre aide @leipert .

Ce fil a été automatiquement verrouillé puisqu'il n'y a eu aucune activité récente après sa fermeture. Veuillez ouvrir un nouveau problème pour les bogues associés.

Cette page vous a été utile?
0 / 5 - 0 notes