Cucumber step definitions in java

Step Definitions

A Step Definition is a method function block function function with an expression that links it to one or more Gherkin steps. When Cucumber executes a Gherkin step in a scenario, it will look for a matching step definition to execute.

To illustrate how this works, look at the following Gherkin Scenario:

Scenario: Some cukes Given I have 48 cukes in my belly 

The I have 48 cukes in my belly part of the step (the text following the Given keyword) will match the following step definition:

package com.example; import io.cucumber.java.en.Given; public class StepDefinitions < @Given("I have cukes in my belly") public void i_have_n_cukes_in_my_belly(int cukes) < System.out.format("Cukes: %n\n", cukes); >> 
package com.example; import io.cucumber.java8.En; public class StepDefinitions implements En < public StepDefinitions() < Given("I have cukes in my belly", (Integer cukes) -> < System.out.format("Cukes: %n\n", cukes); >); > > 
package com.example import io.cucumber.java8.En class StepDefinitions : En < init < Given("I have cukes in my belly") < cukes: Int ->println("Cukes: $cukes") > > > 
package com.example import io.cucumber.java8.En class StepDefinitions : En < init < Given("I have cukes in my belly") < cukes: Int ->println("Cukes: $cukes") > > > 
package com.example import io.cucumber.scala. class StepDefinitions extends ScalaDsl with EN < Given("I have cukes in my belly") < cukes: Int =>println(s"Cukes: $cukes") > > 
Given('I have cukes in my belly') do |cukes| puts "Cukes: #" end 
const < Given >= require('cucumber') Given('I have cukes in my belly', function (cukes) < console.log(`Cukes: $`) >); 

Expressions

A step definition’s expression can either be a Regular Expression or a Cucumber Expression. The examples in this section use Cucumber Expressions. If you prefer to use Regular Expressions, each capture group capture group capture group output parameter output parameter from the match will be passed as arguments to the step definition’s method function block function function .

@Given("I have cukes in my belly") public void i_have_n_cukes_in_my_belly(int cukes)
Given("I have cukes in my belly") < cukes: Int ->println("Cukes: $cukes") > 
Given("I have cukes in my belly") < cukes: Int =>println(s"Cukes: $cukes") > 
Given(/I have cukes in my belly/) do |cukes| end 
Given(/I have cukes in my belly/, function (cukes) < >); 

If the capture group capture group capture group output parameter output parameter expression is identical to one of the registered parameter types’s regexp , the captured string will be transformed before it is passed to the step definition’s method function block function function . In the example above, the cukes argument will be an integer, because the built-in int parameter type’s regexp is \d+ .

Читайте также:  Mask image gradient css

State management

A step definition can transfer state to a subsequent step definition by storing state in instance variables.

Please note that if you use arrow functions, you won’t be able to share state between steps!

Given('I have cukes in my belly', cukes => < // Don't do this. The value of "this" is the "global" object this.cukes = cukes >) 

Scope

Step definitions aren’t linked to a particular feature file or scenario. The file, class or package name of a step definition does not affect what Gherkin steps it will match. The only thing that matters is the step definition’s expression.

Snippets

When Cucumber encounters a Gherkin step without a matching step definition, it will print a step definition snippet with a matching Cucumber Expression. You can use this as a starting point for new step definitions.

Consider this Gherkin step:

If you don’t have a matching step definition, Cucumber will suggest the following snippet:

@Given("I have red balls") public void i_have_red_balls(int int1)
Given('I have red balls') do |int1| end 
Given("I have red balls", function (int1) < >); 

Suggested snippets will use your own parameter types if they match parts of your undefined step. If a color parameter type exists, Cucumber would use that in the suggested expression:

@Given("I have  balls") public void i_have_color_balls(int int1, Color color)
Given('I have  balls') do |int1, color| end 
Given("I have  balls", function (int1, color) < >); 

Make sure you use the summary plugin when running Cucumber in order to have the snippets printed.

You can help us improve this documentation. Edit this page.

Источник

Step Organization

You can have all of your step definitions in one file, or in multiple files. When you start with your project, all your step definitions will probably be in one file. As your project grows, you should split your step definitions into meaningful groups in different files. This will make your project more logical and easier to maintain.

How Cucumber finds your features and step definitions

Be aware that, regardless of the directory structure employed, Cucumber effectively flattens the features/ directory tree when running tests. This means that anything ending in .java .kt .js .rb .go inside the directory in which Cucumber is run is treated as a step definition. In the same directory, Cucumber will search for a Feature corresponding to that step definition. This is either the default case or the location specified with the relevant relevant relevant -r relevant option.

Grouping step definitions

Technically it doesn’t matter how you name your step definition files, or which step definitions you put in a file. You could have one giant file containing all your step definitions. However, as the project grows, the file can become messy and hard to maintain. Instead, we recommend creating a separate *_steps.rb StepDefinitions.java StepDefinitions.kt *_steps.js *_steps.go file for each domain concept.

A good rule of thumb is to have one file for each major model/database table. domain object. domain object. domain object. domain object.

For example, in a Curriculum Vitae application, we might have:

  • employee_steps.rb
  • education_steps.rb
  • experience_steps.rb
  • authentication_steps.rb
  • EmployeeStepDefinitions.java
  • EducationStepDefinitions.java
  • ExperienceStepDefinitions.java
  • AuthenticationStepDefinitions.java
  • EmployeeStepDefinitions.kt
  • EducationStepDefinitions.kt
  • ExperienceStepDefinitions.kt
  • AuthenticationStepDefinitions.kt
  • employee_steps.js
  • education_steps.js
  • experience_steps.js
  • authentication_steps.js
  • employee_steps.go
  • education_steps.go
  • experience_steps.go
  • authentication_steps.go

The first three files would define all the Given , When , and Then step definitions related to creating, reading, updating, and deleting the various models. types of objects. types of objects. types of objects. The last file would define step definitions related to logging in and out, and the different things a certain user is allowed to do in the system.

If you follow this pattern, you also avoid the Feature-coupled step definitions anti-pattern.

Of course, how you group your step definitions is really up to you and your team. They should be grouped in a way that is meaningful to your project.

Writing step definitions

Don’t write step definitions for steps that are not present in one of your scenarios. These might end up as unused cruft that will need to be cleaned up later. Only implement step definitions that you actually need. You can always refactor your code as your project grows.

Avoid duplication

Avoid writing similar step definitions, as they can lead to clutter. While documenting your steps helps, making use of helper methods to abstract them can do wonders.

For example, take the following steps:

 Given I go to the home page Given I check the about page of the website Given I get the contact details 

If all of these steps open their respective web pages, you might be writing redundant steps. While the underlying code for these steps could be different, their behaviour is essentially the same, i.e. to open the Home, About or Contact page.

As such, you can use abstract helper methods to reduce them into a single step:

And the following step definition:

@Given("I go to the page") public void i_want_to_open_page(String webpage)
 Given("I go to the page", function (webpage)
 Given 'I go to the page' do |page| open_web_page page end 
@Given("I go to the page") fun `I want to open page`(webpage: String)
s.Step(`^I go to the "([^"]*)" page$`, goToPage) func goToPage(webpage string) error

Your step definitions are the glue to the actual code (in this example, a factory method to decide which page to open). They can also be used to hide implementation details by calling several reusable helper methods from one step definition.

This helps in a number of ways:

  • Increased maintainability.
  • Increased scalability with reusable steps.
  • More understandable tests.

You can handle other behaviours, like validating a web page, clicking a button, etc., the same way.

We suggest taking a look at the Factory Design Pattern as well. We suggest taking a look at the Factory Design Pattern as well. We suggest taking a look at the Factory Design Pattern as well. Also, using Data Tables for providing inputs to steps helps increase maintainability and understandability.

Helper methods

Always keep in mind that Cucumber is a DSL wrapper around the programming language whose full expressiveness remains available to you in the step definition files (but not in feature files). On the other hand, do not lose sight that every step called as such in a step definition file is first parsed by Gherkin and therefore must conform to the same syntax as used in feature files.

In fact, it is recommended to refactor step definitions into helper methods for greater modularity and reuse. The method can reside in the same .java .kt .js .rb .go file as the step definition.

This makes your project more understandable for people who join your project at a later date; which also makes your project easier to maintain.

You can help us improve this documentation. Edit this page.

Источник

Оцените статью