2013-10-28 22 views
5

Staramy się implementować globalne przechwyty w naszych testach specflow i nie jesteśmy do końca pewni, jak działają przypisane metody [BeforeScenario] i [AfterScenario].Etapy Global [BeforeScenario], [AfterScenario] w SpecFlow

Tak jak to widziałem, te atrybuty są zawsze definiowane w klasie zawierającej określone kroki używane w kilku scenariuszach.

Czy mogą gdzieś pójść, aby zastosować się do wszystkich scenariuszy? A może przypisywanie metod za pomocą [BeforeScenario] i [AfterScenario] powoduje, że są one uruchamiane dla wszystkich scenariuszy, niezależnie od miejsca, w którym zostały umieszczone?

+0

AlSki i Truan mają rację, ta odpowiedź nie działa zgodnie z oczekiwaniami. Nie akceptuj tego i zaakceptuj Alkskiego, a ja usunę odpowiedź. –

Odpowiedz

7

Tak, można utworzyć globalne metody PrzedScenariusz i AfterScenario, ale w praktyce okazało się, że nie jest to pożądane, ponieważ zwykle takie same przed i po krokach nie mają zastosowania do kroków w projekcie testowym.

Zamiast tego, tworzę klasę podstawową dla moich definicji kroków, które miałyby metody PrzedScenariusz i AfterScenarios, które chciałbym zastosować do wszystkich moich scenariuszy, np.

public class BaseStepDefinitions 
{ 
    [BeforeScenario] 
    public void BeforeScenario() 
    { 
     // BeforeScenario code 
    } 

    [AfterScenario] 
    public void AfterScenario() 
    { 
     // AfterScenario code 
    } 
} 

Należy zauważyć, że nie użyłem atrybutu Powiązanie dla tej klasy. Jeśli to uwzględnisz, kroki BeforeScenario i AfterScenario będą globalne.

Następnie wyprowadzam moje klasy definicji kroków z tej klasy definicji kroku podstawowego, aby miały one metody scenariusza Przed i Po, np.

[Binding] 
public class SpecFlowFeature1Steps : BaseStepDefinitions 
{ 
    [Given(@"I have entered (.*) into the calculator")] 
    public void GivenIHaveEnteredIntoTheCalculator(int inputValue) 
    { 
     ScenarioContext.Current.Pending(); 
    } 

    [When(@"I press add")] 
    public void WhenIPressAdd() 
    { 
     ScenarioContext.Current.Pending(); 
    } 

    [Then(@"the result should be (.*) on the screen")] 
    public void ThenTheResultShouldBeOnTheScreen(int expectedResult) 
    { 
     ScenarioContext.Current.Pending(); 
    } 
} 

Podczas gdy takie podejście nie ma charakteru globalnego, dzięki wprowadzeniu wszystkich definicji Etapu z klasy BaseStepDefinition osiągamy ten sam wynik.

Daje również większą kontrolę, tj. Jeśli nie chcesz wiązania wiązania BeforeScenario lub AfterScenario, nie wyprowadzaj go z kroków podstawowych.


Niestety to nie działa. Jak tylko zaczniesz korzystać z wielu klas Binding, otrzymasz wiele połączeń. Na przykład, jeśli mogę przedłużyć powyższy przykład podzielić na trzy klasy wiązań,

[Binding] 
public class SpecFlowFeature1Steps : BaseStepDefinitions 
{ 
    [Given(@"I have entered (.*) into the calculator")] 
    public void GivenIHaveEnteredIntoTheCalculator(int inputValue) 
    { 
     //ScenarioContext.Current.Pending(); 
    } 
} 

[Binding] 
public class SpecFlowFeature2Steps : BaseStepDefinitions 
{ 
    [When(@"I press add")] 
    public void WhenIPressAdd() 
    { 
     //ScenarioContext.Current.Pending(); 
    } 
} 

[Binding] 
public class SpecFlowFeature3Steps : BaseStepDefinitions 
{ 
    [Then(@"the result should be (.*) on the screen")] 
    public void ThenTheResultShouldBeOnTheScreen(int expectedResult) 
    { 
     //ScenarioContext.Current.Pending(); 
    } 
} 

public class BaseStepDefinitions 
{ 
    [BeforeScenario] 
    public void BeforeScenario() 
    { 
     // BeforeScenario code 
     Console.WriteLine("Before. [Called from "+ this.GetType().Name+"]"); 
    } 

    [AfterScenario] 
    public void AfterScenario() 
    { 
     // AfterScenario code 
     Console.WriteLine("After. [Called from " + this.GetType().Name + "]"); 
    } 
} 

Wtedy, kiedy go uruchomić, wyjście jest

Before. [Called from SpecFlowFeature1Steps] 
Before. [Called from SpecFlowFeature2Steps] 
Before. [Called from SpecFlowFeature3Steps] 
Given I have entered 50 into the calculator 
-> done: SpecFlowFeature1Steps.GivenIHaveEnteredIntoTheCalculator(50) (0.0s) 
And I have entered 70 into the calculator 
-> done: SpecFlowFeature1Steps.GivenIHaveEnteredIntoTheCalculator(70) (0.0s) 
When I press add 
-> done: SpecFlowFeature2Steps.WhenIPressAdd() (0.0s) 
Then the result should be 120 on the screen 
-> done: SpecFlowFeature3Steps.ThenTheResultShouldBeOnTheScreen(120) (0.0s) 
After. [Called from SpecFlowFeature1Steps] 
After. [Called from SpecFlowFeature2Steps] 
After. [Called from SpecFlowFeature3Steps] 
+0

Przedłużając przykład z AlSki, możesz pokazać, że te metody wciąż są globalne. dodać 'scenariusz: Zobacz, czy hak BeforeSpecification pobiera nazywane nadal Biorąc nic else' następnie dokonać definicji krok dla' JustTheTest' dziedziczą 'Unrelated' i usunąć' [Oprawa] '' z Unrelated' i dodać ' [Oprawa] public class AnotherTestNotUsingBase { [Zważywszy (@ "nic innego")] public void GivenNothingElse () { // robić nic innego } } ' – Truan

+0

nadal dostać ' Jestem nadal globalny Nie podano nic -> done: JustTheTest.GivenNothing() (0.0s) Nadal jestem globalny Nie podano nic innego -> done: AnotherTestNotUsingBase.GivenNothingElse() (0.0s) ' – Truan

+0

@BenSmith Przepraszamy za edycję twojego posta, ale wygląda na to, że to nie działa. Potrafisz również potwierdzić – AlSki

9

Hmm ... Z tego co wiedział, a według dokumentacja te haki są zawsze globalne, czyli od http://www.specflow.org/documentation/hooks/

haki

haki (bi wydarzenie ndings) może być użyty do wykonania dodatkowej logiki automatyzacji w określonych zdarzeniach, np. przed wykonaniem scenariusza.

Haki są globalne, ale można je ograniczyć do uruchamiania tylko dla funkcji lub scenariuszy z konkretną etykietą (patrz poniżej). Kolejność wykonywania haków dla tego samego zdarzenia jest niezdefiniowana.

W rzeczywistości poprzez produkcję małego projektu demo z następującym

[Binding] 
public class Unrelated 
{ 
    [BeforeScenario] 
    public void WillBeCalledIfGlobal() 
    { 
    Console.WriteLine("I'm global"); 
    } 
} 

[Binding] 
public class JustTheTest 
{ 
    [Given("nothing")] 
    public void GivenNothing() 
    { 
    // Don't do anything 
    } 
} 

Następnie specyfikacja test

As a developer 
In order to understand how BeforeSpecifcation works 
I want to know what the following does 

Scenario: See if BeforeSpecifcation hook gets called 
Given nothing 

Get wyjście

I'm global 
Given nothing 
-> done: JustTheTest.GivenNothing() (0.0s) 

tak naprawdę wygląda tak, jakby dokumentacja była poprawna, i tak Powinieneś używać tagowania do kontrolowania, czy BeforeScenario \ AfterScenario są uruchamiane przed lub po twoim scenariuszu.

Jest również dobrym przykładem tego, jak tagowanie działa tutaj ->Feature-scoped step definitions with SpecFlow?

3

Co można zrobić, aby kontrolować „BeforeScenario” oraz „” jest AfterScenario znaczniki ruchu. Daje to kontrolę nad tym, który scenariusz powinien zostać uruchomiony, przed i po bloku. Twój scenariusz wyglądałby następująco:

@GoogleChrome 
Scenario: Clicking on a button 
    Given the user is on some page 
    When the user clicks a button 
    Then something should happen 

Tutaj można pozwolić „BeforeScenario” rozpocząć sesję przeglądarki w Google Chrome dla ciebie, i wdrożenie podobnych tagów dla różnych przeglądarek. Twój „BeforeScenario” będzie wyglądać następująco:

[Binding] 
class Browser 
{   
    [BeforeScenario("GoogleChrome")] 
    public static void BeforeChromeScenario() 
    { 
     // Start Browser session and do stuff 
    } 

    [AfterScenario("GoogleChrome")] 
    public static void AfterChromeScenario() 
    { 
     // Close the scenario properly 
    } 

myślę użyciu tagów, jest to dobry sposób na utrzymanie Twój scenariusz jest czysty i daje dodatkową funkcjonalność pozwalają kontrolować, co każdy scenariusz powinien zrobić.