Réutiliser les étapes de concombre

Je veux réutiliser quelques étapes de concombre mais je n'arrive pas à trouver le bon chemin.

Je veux écrire une étape comme:

Given /^I login with (.*) credentials$/ |type|
  # do stuff with type being one of "invalid" or "valid"
end

Mais alors avoir une autre étape comme:

Given /^I login successfully$
  # call "Given I login with valid credentials"
end

Donc, en testant l'authentification de l'utilisateur, je peux utiliser le premier, mais la plupart des autres endroits, je peux utiliser le dernier, et ne pas avoir à reproduire le code.

Existe-t-il un moyen d'appeler cette autre étape, ou est-ce que je viens de mettre la logique dans une méthode d'AIDE, et d'appeler cette méthode à partir de chaque tâche (essentiellement une extraction de méthode refactoring, qui, après avoir lu ma question me fait croire que c'est en fait le meilleur moyen de toute façon)?

94
demandé sur Stipe Kolovrat 2009-05-28 01:20:45

5 réponses

UPDATE : la méthode décrite ci-dessous a été obsolète. La façon recommandée d'appeler une étape à partir d'une autre étape ressemble maintenant à ceci:

Given /^I login successfully$/
    step "I login with valid credentials" 
end 

ancienne méthode obsolète (pour référence):

Vous pouvez appeler des étapes à partir d'autres étapes comme ceci:

Given /^I login successfully$/
  Given "I login with valid credentials"
  Then "I should be logged in"
end

Si tous les scénarios d'une entité l'exigent (ou d'autres étapes), vous pouvez également ajouter un arrière-plan à chaque entité, avec les étapes communes, comme ceci:

Background:
  Given I log in with valid credentials

Scenario: Change my password
  Given I am on the account page
99
répondu tomafro 2015-09-27 15:01:23

Notez que la méthode d'appel des étapes dans les étapes a changé dans les versions récentes de cucumber, que vous verrez si vous obtenez une erreur comme "avertissement: L'utilisation de' Given / When / Then 'dans les définitions d'étape est obsolète, utilisez 'step' pour appeler d'autres étapes à la place: / path / to / step_definitions/foo_steps.rb:631:dans le `bloc ' ". Voir le concombre wiki pour plus de détails.

L'essentiel du changement est que vous devriez maintenant utiliser les méthodes step ou steps.

When /^I make all my stuff shiny$/
  step "I polish my first thing"
end

When /^I make all my stuff shiny$/
  steps %Q{
    When I polish my first thing
    When I shine my second thing
  }
end
101
répondu michaeltwofish 2011-12-06 05:24:59

Appeler des étapes à partir de définitions d'étapes est une mauvaise pratique et a quelques inconvénients :

  1. Si le scénario échoue et qu'il y a des invocations d'étape imbriquées, vous n'obtiendrez que la dernière définition d'étape invoquée dans la trace de la pile. Il peut être difficile de trouver à partir de quel endroit ce dernier stepdef a été appelé
  2. L'appel à stepdef est parfois plus difficile à trouver et à lire que la méthode ruby
  3. Les méthodes Ruby vous donnent plus de pouvoir que d'appeler des étapes à partir de Step defs

Aslak Hellesøy recommande à d'extraire les actions populaires dans World au lieu de réutiliser les étapes. Il isole ces actions en un seul endroit, rend ce code plus facile à trouver. Vous pouvez également extraire du code dans les classes ou modules Ruby habituels.

#/support/world_extensions.rb
module KnowsUser
  def login
    visit('/login')
    fill_in('User name', with: user.name)
    fill_in('Password', with: user.password)
    click_button('Log in')
  end

  def user
    @user ||= User.create!(:name => 'Aslak', :password => 'xyz')
  end
end
World(KnowsUser)

#/step_definitions/authentication_steps.rb
When /^I login$/ do
  login
end

Given /^a logged in user$/ do
  login
end

Voici une discussion utile sur le sujet dans le Concombre liste de diffusion - lien

41
répondu Andrei Botalov 2017-07-07 11:54:14

Mieux envelopper vos étapes dans % {} plutôt que des guillemets. Ensuite, vous n'avez pas besoin d'échapper aux guillemets doubles que vous devrez utiliser fréquemment.:

Given /^I login successfully$
  step %{I login with valid credentials}
end

Given /^I login with (.*) credentials$/ |type|
  # do stuff with type being one of "invalid" or "valid"
end
9
répondu Rimian 2012-02-21 03:22:55

Réutiliser les mots-clés dans le fichier de fonctionnalité qui fournira la réutilisabilité du code.

Il est fortement déconseillé d'appeler step defs dans step defs.

J'écrirais mon fichier de fonctionnalité de cette façon,

Scenario Outline: To check login functionality
    Given I login with "<username>" and "<password>"
    Then I "<may or may not>" login successfully

Examples:
    |username|password|may or may not|
    |paul    |123$    |may           |
    |dave    |1111    |may not       |

Dans ma définition d'étape, (C'est Java)

@Given(I login with \"([^\"]*)\" and \"([^\"]*)\"$)
public void I_login_with_and(String username, String password){

   //login with username and password

}

@Then(I \"([^\"]*)\" login successfully$)
public void I_login_successully_if(String validity){

    if(validity.equals("may")){
        //assert for valid login
    }
    else
    if(validity.equals("may not")){
        //assert for invalid login
    }
}

De cette façon, il y a beaucoup de réutilisabilité du code. Votre même donné et gère ensuite les scénarios valides et invalides. En même temps, votre fichier de fonctionnalités a du sens pour les lecteurs.

1
répondu LINGS 2013-06-10 15:31:32