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)?
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
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
Appeler des étapes à partir de définitions d'étapes est une mauvaise pratique et a quelques inconvénients :
- 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é
- L'appel à stepdef est parfois plus difficile à trouver et à lire que la méthode ruby
- 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
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
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.