Specflow – kroki o tej samej nazwie ale z inną implementacją

W poprzednim poście, pisałem jak są współdzielone kroki między różnymi scenariuszami. Jeśli tylko zostaną one rozdzielone odpowiednio między klasy, zestaw testów stanie się po prostu łatwiejszy w utrzymaniu. Dzięki temu nie musimy duplikować kodu. Oczywiście pokazałem również jak nie należy pisać testów ponieważ stosunkowo łatwo w SpecFlow można “rozsynchronizować” plik z opisem scenariuszu z klasami implementującymi kolejne kroki.

Przede wszystkim jeśli jakiś krok ma identyczny opis w dwóch scenariuszach, naturalne jest, że domyślna implementacja jest współdzielona. Jeśli oczekujemy kompletnie innej implementacji, wtedy być może powinniśmy zmienić opis tego kroku. W praktyce jednak zdarzają się sytuacje, kiedy np. Given jest taki sam, ale chcemy napisać kompletnie inny kod.  Załóżmy, że mamy scenariusze z poprzedniego postu:

Feature: NewPost Jakis opis tutaj... Scenario: Create a new post Given I have logged into CMS When I press the create a post button Then article should be created.

Feature: EditPost Jakis opis tutaj... Scenario: Edit a post Given I have logged into CMS When I press the edit a post button Then article should be updated.

Jak wspomniałem wcześniej, chcemy dostarczyć dwie różne implementacje dla given. Domyślnie, zostaną one współdzielone. W SpecFlow możemy skorzystać z atrybutu Scope. Spróbujmy najpierw wstawić ręcznie given dla powyższych dwóch scenariuszy:

[Binding] public class EditPostSteps { [Given(@"I have logged into CMS")] public void GivenIHaveLoggedIntoCMS() { } [When(@"I press the edit a post button")] public void WhenIPressTheEditAPostButton() { } [Then(@"article should be updated\.")] public void ThenArticleShouldBeUpdated_() { ScenarioContext.Current.Pending(); } }

[Binding] public class NewPostSteps { [Given(@"I have logged into CMS")] public void GivenIHaveLoggedIntoCMS() { } [When(@"I press the create a post button")] public void WhenIPressTheCreateAPostButton() { ScenarioContext.Current.Pending(); } [Then(@"article should be created\.")] public void ThenArticleShouldBeCreated_() { ScenarioContext.Current.Pending(); } }

Po uruchomieniu kodu dostaniemy wyjątek:

Additional information: Ambiguous step definitions found for step 'Given I have logged into CMS': EditPostSteps.GivenIHaveLoggedIntoCMS(), NewPostSteps.GivenIHaveLoggedIntoCMS()

Nic dziwnego, kroki (wiązania) jak wiemy są globalne.  Za pomocą atrybutu scope możemy zawęzić  nasze poszukiwania:

[Given(@"I have logged into CMS")] [Scope(Feature = "EditPost")] public void GivenIHaveLoggedIntoCMS() { }

W tej chwili wszystko skompiluje się bez problemów ponieważ powyższy Given jest przeznaczony wyłącznie dla scenariuszy EditPost. Atrybut nie ogranicza się wyłącznie do nazwy feature:

[Scope(Tag = "mytag", Feature = "feature title", Scenario = "scenario title")]

Title to tytuł scenariusza:

[Given(@"I have logged into CMS")] [Scope(Feature = "Edit a post")] public void GivenIHaveLoggedIntoCMS() { }

Możliwa jest również identyfikacja za pomocą samego tagu:

[Given(@"I have logged into CMS")] [Scope(Tag = "myFirstTag")] public void GivenIHaveLoggedIntoCMS() { }

Musimy również zaktualizować feature file, dodając tag:

@myFirstTag Feature: EditPost Jakis opis tutaj... Scenario: Edit a post Given I have logged into CMS When I press the edit a post button Then article should be updated.

Leave a Reply

Your email address will not be published.