How to increase the reuse of SpecFlow / Gherkin steps?

I think I fully understand SpecFlow's concepts and ideas, but even after reading Secret Ninja Cucumber Scrolls , Cucumber Book , and going through various forums, I'm still not sure about the path to reuse.

Our scenarios already comply with various recommendations.

  • Self catering
  • Must have an understandable purpose (which sets it apart from other scenarios)
  • Unique
  • Presentation of vertical functional slices
  • Using Ubiquitous Language
  • Written from a stakeholder perspective
  • About business functionality, not software development.
  • Grouped by Epics
  • NOT TEST REGISTRATION
  • Have someone else read them to make sure the script is correct.
  • Not applicable to user interface elements.
  • Present key examples
  • Non-technical
  • Accurate and verifiable
  • As far as possible repeatability
  • “Data” represents a state, not an action.
  • 'When' represent actions
  • 'Then' should represent a visible change, not some kind of internal event

Our steps should comply with the following recommendations (some of them relate to SpecFlow):

  • Using Ubiquitous Language
  • Not applicable to user interface elements.
  • Should not be combined
  • It must be multiple and global in all functions.
  • Should not be tied to a specific function
  • Grouped by objects, entity groups, or domain concepts.
  • Do not create steps to reuse logic in the step definition file
  • Carefully consider in which step the file that belongs to the step is located.
  • Do not repeat steps between phases
  • Letter strings should be avoided in steps, but use single quotes if necessary
  • Never apply multiple attributes [Given], [When] or [Then] to the Method step
  • Order the steps according to the phase they represent.
  • If this is not important for the scenario, it is very important not to mention it

But we still get many variations of the same steps, even if we use regex placeholders. Especially the rule is that if something is not important, you should not mention that this leads to these changes. And yes, internally these steps do a lot of reuse, but not in the script.

Consider, for example, the following scenario:

Feature: Signing where both persons are physically available @Smoke Scenario: Show remaining time to sign based on previous signature Given a draft proposal And the first signature has been set When I try to set the second signature Then the remaining time to sign should be shown @Smoke Scenario: Re-signing of the first proposal Given a signature that has not been set within the configured time And the first signature has just been re-signed When I try to set the second signature Then the remaining time should start over 

Would it be better to combine the two “given” steps into one and lose some reusability?

Some other examples:

 Feature: Conditionally show signatures to be signed @Smoke Scenario: Show the correct signature for a proposal with a night shift Given I have a proposal for the day shift When I change it to the night shift Then I should only be able to sign for the night shift @Smoke Scenario: Show additional signature when extending the shift Given I have a suspended proposal for the night shift When I extend the period to the day shift Then I should confirm extening the period over the shift 

Did I miss the fundamental concept here?

+7
source share
2 answers

This is not an answer, but some tips:

  • you can put multiple Given / When / Then attributes in the same method. If the parameters are the same, and the difference is only in phrasing, this can be useful
  • in many projects, we use the driver / page template template, so the definitions of steps are usually quite short (2-3 lines), so we worry less about the number
  • I like your scripts, I would not change them. On the other hand, try focusing on readability rather than reuse. If your language is consistent, reuse will come.
  • To increase reuse, especially when there are many “variations” of the object you are talking about, you can use step argument conversions . Here is an example:

you need a class to represent resolution in tests with decorations:

 class PermitDescription{ bool suspended; bool draft; } 

create converter methods:

 [StepArgumentTransformation("permit")] public PermitDescription CreateSimple(){ return new PermitDescription(); } [StepArgumentTransformation("draft permit")] public PermitDescription CreateDraft(){ return new PermitDescription() { draft = true; } } [StepArgumentTransformation("suspended permit")] public PermitDescription CreateSuspended(){ return new PermitDescription() { suspended = true; } } 

you can now have more flexible step definitions requiring permissions:

 [Given(@"I have a (.*) for the day shift")] public void Something(PermitDescription p) { ... } 

which corresponds to:

 Given I have a permit for the day shift Given I have a draft permit for the day shift Given I have a suspended permit for the day shift 

Of course, this is a tool that can also be abused, but in some cases it can help.

+12
source

Adding to the answer from @ gaspar-nagy This follows the design of the class in C programming. In any case, the common group of classes has common properties / methods, these properties / methods can be reorganized into a base class.

In our SpecFlow tests, it looks like this: common browser functions are in the base classes:

 Login() Logout() NavigateToUrl(string url) UserHasPermission(string permission) WaitForElementToAppearById(string id) WaitForElementToAppearByClass(string class) 

And each of these methods can have 1 or more Given / When / Then attributes, indicated as @ gasper-nagy.

Another method that is invaluable is to share variables between .features and their corresponding C # step files to use ScenarioContext.

For example, whenever Login() is called to initiate our browser-based tests, we do the following:
ScenarioContext.Current.Set<IWebDriver>(driver, "driver")

Then in any other place where you need a driver, you can get it:
var driver = ScenarioContext.Current.Get<IWebDriver>("driver")

This leads to the reuse of steps, for example, to custom input tests for validation, which you can take to pass the element to be checked as follows: ScenarioContext.Current.Set<IWebElement>(element, "validation-element")

0
source

All Articles