2013-03-19 10 views
7

ho almeno 3 file .Feature nel mio progetto C# test Specflow in cui ho il passo, per esempio:file Feature Specflow con gli stessi passaggi che causano più istanze del browser per lanciare

Given I am at the Home Page

Quando ho prima ha scritto il passo nel file Feateure1.feature e ha creato il metodo passo, ho messo in un file passo, diciamo, Steps1.cs, che eredita da una classe base che inizializza una FirefoxDriver. Tutte le mie classi StepsXXXX.cs ereditano da questa classe base.

Quindi, ho scritto Feature2.feature, che ha anche un passo Given I am at the Home Page. E il passo è stato automaticamente legato a quello di Steps1.cs

'Fino ad ora, nessun problema. Questo è praticamente ciò che volevo - avere passaggi riutilizzabili per tutto il progetto di test. Ma il problema è che, ogni volta che eseguo uno scenario che presenta passaggi in diversi file StepsXXXX, ottengo varie istanze del browser in esecuzione.

======

Sono abbastanza sicuro che questo è dovuto al fatto che il mio StepsXXXX (classi vincolante) tutto ereditano da questa classe di base che ha un'IWebDriver propria, e quando il passo viene chiamato, viene chiamato tutto il resto (compresi i metodi dello scenario before/after). Ma non riesco a capire come aggirare questo.

Voglio ancora i passaggi riutilizzabili. Ho provato a mettere questi passaggi nella classe base, ma non ha funzionato. Ho pensato di cambiare anche i binding, ma specflow usa stringhe significative per farlo, e non voglio cambiarli in stringhe fuorvianti.

Qualcuno si è imbattuto in questo? Qualsiasi aiuto è molto apprezzato.

risposta

5

Il problema è che i binding SpecFlow non rispettano l'ereditarietà. Tutti gli attributi personalizzati sono considerati globali e quindi tutto ciò che SpecFlow fa è cercare un elenco di classi con una [Binding], quindi creare un dizionario per tutti i [Given]/[When]/[Then] s in modo che possa valutarli per una migliore corrispondenza. Quindi creerà un'istanza della classe (se non lo ha già fatto) e chiamerà il metodo su di essa.

Di conseguenza i vostri casi semplici tutte rimanere nella classe steps1, perché la sua la prima partita perfetta. I tuoi casi più complicati iniziano a istanziare più classi, quindi più browser, e il tuo tentativo di refactoring non funzionerà perché la tua classe base astratta non ha una [Binding] su di essa.

probabilmente sarei iniziare appiattendo tutto il vostro gerarchia delle classi passo, in una grande classe di AllSteps.cs. Questo può sembrare controproducente, ma tutto ciò che si sta facendo è sistemare il codice su come appaiono i collegamenti correnti alle caratteristiche di SpecFlow. In questo modo è possibile iniziare a ridefinire le sovrapposizioni tra i diversi binding GWT.

Al momento i tuoi attacchi sono disposti attorno agli scenari. Quello che devi fare è refactoring attorno alla tua funzionalità. Leggi una recensione di Whose Domain is it anyway? prima di iniziare e questo probabilmente ti darà delle buone idee. Quindi dai uno sguardo a Sharing-Data-between-Bindings sulla documentazione di SpecFlow per capire come collegare tra le tue nuove classi di passaggi.

2

Ho affrontato lo stesso problema.

Volevo avere un file di funzionalità che chiamerà i passaggi in diverse classi cs. Il problema si è verificato quando voglio impostare e abbattere per ogni scenario.

L'utilizzo del costruttore della classe di passi e Dispose() non è possibile perché lo scenario utilizza più di una classe di passaggi che non si desidera "configurare" più volte in uno scenario.

L'utilizzo di [BeforeScenario] e [AfterScenario] per entrambe le classi di fasi fa sì che il runner esegua i metodi before e after in entrambe le classi, il che rende l'installazione eseguita due volte.

Quindi, ciò che è stato fatto è creare un'altra terza classe chiamata qualcosa come BrowserScenarioSetup inserire la classe di scenario precedente e successiva in essa per impostare un browser per lo scenario e assegnare al dizionario ScenarioContext.Current. Quando si esegue il test, viene creato un solo browser per uno scenario e io posso utilizzare i passaggi dello scenario definiti in qualsiasi classe, ma solo Scenario.Context.Current per ottenere l'istanza del browser.

posso fare entrambe le classi di passo hanno una classe di passo di base e creare un breve metodo per ottenere istanza del browser (o qualsiasi istanza condivisa creata nel setup) solo per nascondere Scenario.Context.Current

Finalmente posso segnare [BeforeScenario("Browser", "IE")] e utilizzare @Browser e @IE in una funzione o scenario per chiamare solo questo metodo di installazione in un contesto appropriato.

1

Penso che questo sia molto più semplice della domanda e le risposte qui lo dimostrano. ci sono davvero due domande qui:

AISki ti ha dato la risposta giusta nel link alla documentazione sul contesto specflow, ma non è stata presentata come la risposta e c'era una distrazione nel presentare una risposta inferiore come risposta reale .

la risposta al comportamento che si vede è che dovresti aspettarti esattamente cosa sta succedendo nel modo in cui imposti le cose. se si hanno più classi di bind che creano istanze di browser (e si fa se hanno tutte una base comune che crea un'istanza di browser) e hanno corrispondenze nelle funzionalità, è necessario prevedere più istanze di browser.

La risposta per ciò che si intende (un singolo browser condiviso tra i passaggi) è che è necessario utilizzare la funzionalità di contesto di specflow per controllare la dipendenza da un'istanza del browser. questo equivale all'iniezione di dipendenza. le tue classi di definizione dei passi dovrebbero prendere una dipendenza costruttore per qualcosa che crea l'istanza del browser - specflow gestisce le dipendenze per te e otterrai una nuova istanza per la prima delle tue classi create e poi la stessa dopo.

https://github.com/techtalk/SpecFlow/wiki/Sharing-Data-between-Bindings

3

È possibile utilizzare Scoped bindings usando [Scope(Tag = "mytag", Feature = "feature title", Scenario = "scenario title")] per cui su specifici scenari o feateure come questo:

Feature: Feateure1 

Scenario: demo 
Given I am at the Home Page 
When .... 

[Binding, Scope(Feature = "Feateure1")] 
public class Steps1{ 

[Given(@"Given I am at the Home Page")] 
public void GivenIAmAtTheHomePage(){ 
    { } 
} 

Feature: Feateure2 

Scenario: demo 
Given I am at the Home Page 
When .... 
... 

[Binding,Scope(Feature = "Feateure2")] 
public class Steps2{ 

[Given(@"Given I am at the Home Page")] 
public void GivenIAmAtTheHomePage(){ 
{ } 

} 
Problemi correlati