2015-03-17 8 views
10

TL; DR; Come posso creare un test di specflow che chiama un altro test come primo passo?In Specflow posso eseguire un test come passo di un altro?

Given I already have one specflow test 
And I want to run another test that goes deeper than the first test 
Then I create a second test that runs the first test as its first step 
And I add additional steps to test the deeper functionality 

Siamo spiacenti, po 'di umorismo specflow lì.

ad esempio ho un test che crea una vendita già:

Given I want to create a sales order 
And I open the sales order page 
And I click the add new order button 
Then a new sales order is created 

E voglio avere un altro test che i test l'aggiunta di una linea di vendita

E un altro test che mette alla prova il completamento della vendita

E un altro test che annulla la vendita

E .. così via

Tutti questi test inizieranno con gli stessi primi quattro passaggi del test semplice, che interrompe il principio DRY. Quindi, come posso fare in modo che il primo passaggio del secondo test esegua solo il primo test? ad esempio, qualcosa come:

Given I have run the create sales order test // right here it just runs the first test 
And I add a sales order line 
Then the order total is updated 

Se ogni prova inizia con gli stessi primi quattro righe, e poi mi rendo conto che ho bisogno di cambiare il semplice creare vendita di prova, poi ho anche bisogno di andare a trovare e correggi ovunque che ripeta quelle quattro righe.

EDIT: Si noti che questo dovrebbe anche essere in grado di lavorare sui lineamenti. ad es. Il test semplice sopra è definito nella funzione di vendita. Ma vorrei anche avere un credito dispongono, e che richiederebbe la creazione di una vendita ogni volta al fine di essere in grado di accreditarlo:

Given I want to credit a sale 
And I run the create sales order test 
And I complete the the sale 
And I click the credit button 
Then the sale is credited 
+0

sta creando il vostro 'dato Ho eseguito il passo di creare ordine di vendita test' che esegue tre precedenti' Given' metodi passi non funziona? O vuoi un altro modo? Dubito che tu voglia ripetere la parte 'Assert' nei tuoi test successivi. –

+0

Non mi dispiace che dovrà ripetere gli asserzioni che esisteranno nel primo test. Voglio essere in grado di eseguirlo senza dover scrivere gli stessi 4 passaggi in molti test diversi. –

+0

sì, ma perché non crei il nuovo 'Given' come la tua parte 'qualcosa del genere', che chiama manualmente i tre' Given' precedenti? Inoltre, si adatta allo scenario nella tua modifica poiché puoi riutilizzare il passaggio "Ho eseguito il test di creazione di un ordine di vendita" dove desideri. Eri al 99% nella tua domanda. –

risposta

12

Come notato già si può usa uno sfondo per questo (e questa è probabilmente l'opzione migliore nella maggior parte delle situazioni), ma puoi anche creare un passo che chiama gli altri passi.

[Binding] 
public class MySteps: Steps //Inheriting this base class is vital or the methods used below won't be available 
{ 
    [Given("I have created an order")] 
    public void CreateOrder() 
    { 
     Given("I want to create a sales order"); 
     Given("I open the sales order page"); 
     Given("I click the add new order button"); 
     Then("a new sales order is created"); 
    } 
} 

che è quindi possibile utilizzare nel vostro scenario:

Scenario: I add another sale 
    Given I have created an order 
    When I add a sales order line 
    Then the order total is updated 

Questo ha il vantaggio che questo passo composito può essere utilizzato in qualsiasi parte del piano d'azione e non solo come punto di partenza. Questo passaggio può quindi essere riutilizzato su più funzioni, se avete bisogno

+0

Grazie, in effetti è abbastanza vicino. Tuttavia, desidero ancora che il primo test abbia i passaggi effettivamente scritti nel file di feature, quindi ci sarà ancora qualche duplicazione (ma solo 2x invece di n volte). –

+0

Va bene. Puoi usare i passaggi se vuoi o puoi raggrupparli insieme con un 'composito' di cui hai bisogno. Dà il meglio di entrambi i lavori –

+0

Un paio di cose di cui diffidare: 1. è necessario utilizzare il dato corretto (...) Quando (...) Quindi (...) o E (...) per abbinare la definizione del passo e 2. se si utilizza un "E" dopo il passo, esso "erediterà" l'ultima volta che è stato utilizzato nel codice, anziché ciò che è stato utilizzato per ultimo nel file di caratteristiche. – Steve

5

utilizzare uno sfondo:

Background: 
    Given I want to create a sales order 
    And I open the sales order page 
    And I click the add new order button 
    Then a new sales order is created 

Scenario: I add another sale 
    When I add a sales order line 
    Then the order total is updated 

Scenario: I add cancel a sale 
    When I cancel a sale 
    Then the order total is updated to 0 

etc. 
+0

Che sembra buono, ma funzionerebbe solo all'interno di una singola funzione, giusto? C'è un modo per riutilizzare il test su più funzionalità? Aggiornerò la domanda –

+0

Puoi usare '[BeforeTestRun]' o '[BeforeScenario]' ma si applicherà ad ogni scenario. Non sono sicuro se è quello che vuoi? – RagtimeWilly

+0

No, sarebbe solo per test specifici correlati. Test che iniziano allo stesso modo, ma poi proseguono per testare qualcosa di più. –

2

Non è necessario eseguire passaggi effettivi per creare un ordine di vendita. Basta implementare una definizione di step che fa questo per te come one-liner.

In primo luogo, l'immaginario SalesOrder classe:

public class SalesOrder 
{ 
    public double Amount { get; set; } 
    public string Description { get; set; } 
} 

Poi le definizioni step

using TechTalk.SpecFlow; 
using TechTalk.SpecFlow.Assist; 

[Binding] 
public class SalesOrderSteps 
{ 
    [Given("I have already created a Sales Order")] 
    public void GivenIHaveAlreadyCreatedASalesOrder() 
    { 
     var order = new SalesOrder() 
     { 
      // .. set default properties 
     }; 

     // Save to scenario context so subsequent steps can access it 
     ScenarioContext.Current.Set<SalesOrder>(order); 

     using (var db = new DatabaseContext()) 
     { 
      db.SalesOrders.Add(order); 
      db.SaveChanges(); 
     } 
    } 

    [Given("I have already created a Sales Order with the following attributes:")] 
    public void GivenIHaveAlreadyCreatedASalesOrderWithTheFollowingAttributes(Table table) 
    { 
     var order = table.CreateInstance<SalesOrder>(); 

     // Save to scenario context so subsequent steps can access it 
     ScenarioContext.Current.Set<SalesOrder>(order); 

     using (var db = new DatabaseContext()) 
     { 
      db.SalesOrders.Add(order); 
      db.SaveChanges(); 
     } 
    } 
} 

Ora è possibile creare ordini di vendita come un one-liner e opzionalmente includere alcuni attributi personalizzati:

Scenario: Something 
    Given I have already created a Sales Order 

Scenario: Something else 
    Given I have already created a Sales Order with the following attributes: 
     | Field  | Value    | 
     | Amount  | 25.99    | 
     | Description | Just a test order | 

Se è necessario accedere a tale SalesOrder eseguire l'oggetto in altre definizioni di passo senza eseguire una query nel database, utilizzare ScenarioContext.Current.Get<SalesOrder>() per recuperare quell'oggetto dal contesto dello scenario.

-1

Se ho compreso correttamente la domanda, si desidera chiamare altri scenari tra diversi file di caratteristiche.

  1. È possibile gestire questo con la creazione di un passo che avrebbe chiamato i passaggi nella scenario (in pratica nidificato passi come la risposta accettata sopra).
  2. Aggiungere il passaggio creato per il Background

o

  1. creare una funzione che chiamare i passaggi dello scenario.
  2. Aggiungi un tag @create_sale_order agli scenari che richiedono un ordine di vendita come precondizione.
  3. implementare un hook scenario di prima per il tag @create_sale_order e chiamare la funzione creata al punto 1.
Problemi correlati