Riutilizza i passaggi del cetriolo


103

Voglio riutilizzare alcuni gradini di cetriolo ma non riesco a trovare la strada giusta.

Voglio scrivere un passaggio come:

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

Ma poi fai un altro passaggio come:

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

Quindi, nel testare l'autenticazione dell'utente, posso usare il primo, ma nella maggior parte degli altri posti, posso usare il secondo e non devo effettivamente riprodurre il codice.

C'è un modo per chiamare quell'altro passaggio, o metto semplicemente la logica in un metodo di supporto e chiamo detto metodo da ogni attività (fondamentalmente un refactoring di estrazione del metodo, che, dopo aver letto la mia domanda, mi fa credere che sia effettivamente il modo migliore Comunque)?


1
Nel caso qualcuno sia confuso, tutti qui tralasciano il donecessario per avviare il do...endblocco nella definizione del passaggio di Ruby. È infatti richiesto.
Shaun Lebron

Risposte:


102

AGGIORNAMENTO : il metodo descritto di seguito è stato deprecato. Il modo consigliato per chiamare un passaggio dall'interno di un altro passaggio ora è simile al seguente:

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

Vecchio metodo obsoleto (per riferimento):

Puoi richiamare i passaggi da altri passaggi come questo:

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

Se tutti gli scenari all'interno di una funzionalità richiedono questo (o altri passaggi), puoi anche aggiungere uno sfondo a ciascuna funzionalità, con i passaggi comuni, in questo modo:

Background:
  Given I log in with valid credentials

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

5
Ancora più facile è incollare il codice del cetriolino in questo modo:steps %Q{Given I am logged in}
BrendanDean

1
@BrendanDean Quando questa risposta è stata accettata, il stepsmetodo non esisteva. Vedi la mia risposta di seguito.
michaeltwofish

Si noti che i passaggi di congiunzione sono ora considerati un anti-pattern e dovrebbero essere evitati. Vedi il wiki di Cucumber - cucumber.io/docs/guides/anti-patterns/…
Jan Molak

103

Tieni presente che il metodo per chiamare i passaggi all'interno di passaggi è cambiato nelle versioni recenti di cucumber, che vedrai se ricevi un errore del tipo "ATTENZIONE: l'utilizzo di" Dato / Quando / Allora "nelle definizioni dei passaggi è obsoleto, utilizza" passaggio "per chiama invece altri passaggi: /path/to/step_definitions/foo_steps.rb: 631: in `block in '". Vedi il wiki del cetriolo per i dettagli.

L'essenza del cambiamento è che ora dovresti usare i metodi stepo 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

18
Per quello che vale, dopo più tempo con Cucumber, consiglio di non usare affatto i passaggi all'interno dei passaggi. I problemi sono difficili da rintracciare e in realtà rende più difficile la manutenzione. Utilizza invece metodi di supporto.
michaeltwofish

2
Forse dovresti includere questo commento nella tua risposta poiché è molto votato e riceve ancora voti. Aiuterà le persone a notare queste informazioni
Andrei Botalov

ciao @michaeltwofish, ci sono cambiamenti nel 2017? Sto diventando syntax error, unexpected tIDENTIFIER, expecting keyword_end stackoverflow.com/questions/43319331/...
ericn

43

Il richiamo dei passaggi dalle definizioni dei passaggi è una cattiva pratica e presenta alcuni svantaggi :

  1. Se lo scenario fallisce e sono presenti richiami di passaggi nidificati, si otterrà solo l'ultima definizione di passaggio richiamato nella traccia dello stack. Potrebbe essere difficile trovare da quale posizione è stato chiamato l'ultimo stepdef
  2. La chiamata a stepdef a volte è più difficile da trovare e leggere rispetto al metodo ruby
  3. I metodi Ruby ti danno più potenza rispetto alla chiamata di passaggi da step defs

Aslak Hellesøy consiglia di estrarre le azioni popolari in World invece di riutilizzare i passaggi. Isola quelle azioni in un unico posto, rende questo codice più facile da trovare. Puoi anche estrarre il codice nelle normali classi o moduli Ruby.

#/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

Ecco un'utile discussione sull'argomento nella mailing list di Cucumber - link


2
Credo che questo approccio sia molto meglio che chiamare le funzioni step o steps per gli stessi motivi sopra menzionati.
pisaruk

2
Questo ha un altro vantaggio. Usando Idea (o Rubymine), puoi saltare facilmente alle definizioni di funzione, ma non ai passaggi nei passaggi% {...}.
slipset

anche questo setup segue il principio DRY
Sorcerer86pt

2
Anche se ho riscontrato il problema del riutilizzo dei passaggi, penso che questo sia solo un male. Il login è solo la somma di diversi passaggi: "visita qualcosa", "riempi qualcosa". Il modo naturale sarebbe riutilizzare i passaggi, invece di convertire ogni passaggio in una chiamata a una funzione. IMO, la chiamata di passaggi all'interno di passaggi dovrebbe essere solo migliorata.
dgmora

9

È meglio racchiudere i passaggi in% {} anziché tra virgolette. Quindi, non è necessario sfuggire alle virgolette doppie che dovrai usare frequentemente .:

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

5
Questo avrebbe dovuto essere un commento invece di una risposta.
Kelvin

1

Riutilizzare le parole chiave nel file di funzionalità che fornirà la riusabilità del codice.

Si sconsiglia vivamente di chiamare step defs all'interno di step defs.

Scriverei il mio file delle caratteristiche in questo modo,

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       |

Nella mia definizione del passaggio, (Questo è 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
    }
}

In questo modo, c'è molta riusabilità del codice. Il tuo stesso dato e quindi gestisce scenari validi e non validi. Allo stesso tempo, il tuo file delle caratteristiche ha senso per i lettori.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.