web-dev-qa-db-fra.com

Réutiliser les étapes du concombre

Je veux réutiliser certaines étapes de concombre mais ne semble pas trouver la bonne façon.

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 faites une autre étape comme:

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

Donc, en testant l'authentification des utilisateurs, je peux utiliser le premier, mais la plupart des autres endroits, je peux utiliser le dernier, sans avoir à reproduire le code.

Existe-t-il un moyen d'appeler cette autre étape, ou dois-je simplement mettre la logique dans une méthode d'assistance, et appeler ladite méthode à partir de chaque tâche (essentiellement une refactorisation d'extraction de méthode, qui, après avoir lu ma question, me fait croire que c'est en fait la meilleure façon en tous cas)?

101
Daniel Huckstep

UPDATE : La méthode décrite ci-dessous est 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 celle-ci:

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

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

Background:
  Given I log in with valid credentials

Scenario: Change my password
  Given I am on the account page
101
tomafro

Notez que la méthode d'appel des étapes dans les étapes a changé dans les versions récentes de concombre, ce que vous verrez si vous obtenez une erreur comme "AVERTISSEMENT: l'utilisation de" Donné/Quand/Alors "dans les définitions d'étape est déconseillée, utilisez" étape "pour appelez d'autres étapes à la place: /path/to/step_definitions/foo_steps.rb: 631: dans `block in '". Voir le wiki concombre pour plus de détails.

L'essentiel de la modification est que vous devez 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
102
michaeltwofish

L'appel d'étapes à partir de définitions d'étapes est une mauvaise pratique et présente certains inconvénients :

  1. Si le scénario échoue et qu'il y a des appels d'étape imbriqués, vous n'obtiendrez que la dernière définition d'étape invoquée dans la trace de pile. Il peut être difficile de trouver à 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 puissance que d'appeler des étapes à partir des étapes de déf.

Aslak Hellesøy recommande pour extraire les actions populaires vers 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 le code des 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 la liste de diffusion Cucumber - link

42
Andrei Botalov

Mieux vaut envelopper vos pas en% {} plutôt qu'en 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
Rimian

Réutilisez les mots-clés dans le fichier de fonctionnalité qui permettront la réutilisation du code.

Il est fortement déconseillé d'appeler les échelons dans les échelons.

J'écrirais mon fichier de fonctionnalités 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éutilisation de code. Vos mêmes données et puis gère les scénarios valides et non valides. Dans le même temps, votre fichier de fonctionnalités a du sens pour les lecteurs.

1
LINGS