Mate Mrše
Mate Mrše

Reputation: 8394

Extending a Cucumber step

I have a Cucumber step that looks like this:

When I enter the credentials for the user

and another that says

When I enter the correct credentials for the user

Corresponding step definitions are:

@When("I enter the ([^\"]*) for the user$")
public void stepDefinition(String cred){
    //code
}
@When("I enter the correct ([^\"]*) for the user$")
public void otherStepDefinition(String cred){
    //other code
}

But my second cucumber step ("I enter the correct credentials for the user") is matched by the first step definition, only with the word "correct" added to the credentials.

  1. How do I fix this?
  2. I'm new to regex. Would it be possible to exclude the "correct" part from the 'When' step so I could have a basic step that could be 'extended' with the "correct" part?

Upvotes: 3

Views: 571

Answers (4)

Martin of Hessle
Martin of Hessle

Reputation: 434

Several answers suggest an imperative approach which is considered an anti-pattern in BDD. Instead I strong suggest you follow the declarative approach with your Gherkin using natural or business language. If you are actually testing the login feature, I'd propose something like:

When an authorised user enters their credentials

or role based

When an Administrator is authorised

If login is actually a prerequisite for the feature under test then something such as:

Given an authorised user

or

Given an authorised Administrator

These can be backed up with a Credentials Manager.

... = ExpectedData.credentialsFor("@authorised");

The tag should represent the characteristics, not the identity of the expected data, to be retrieved from a test data db or csv containing something like:

@admin, administrator, password
@authorised, user, password
@unauthorised, user, wrong

The same approach should be used for all test data entry, such as:

Given a Cash Customer
Given a Credit Customer
Given a Customer with an overdue account

A strong benefit of this approach is the test suit can be readily reused on different environment by making the data/credential handler environment aware.

Upvotes: 2

diabolist
diabolist

Reputation: 4099

There are a couple of ways you could improve these steps and avoid the use of regex.

1) Have the user know its credentials and have the step ask the user for the credentials

So you would have


Given I am a user
  @user = create_user # method creates a user with credentials
end

When `I enter the users credentials` do
  fill_in username: @user.username
  fill_in password: @user.password
end

When `I enter the wrong credentials for the user` do
  fill_in username: @user.username
  fill_in password: @user.bad_password # or perhaps just bad_password
end

this approach removes all the complexity from cucumber and places it in the helper methods you are calling to create a user.

2) Have more arguments for your step definition

When 'I enter the credentials user: (\\S+) password: (\\S+) do |username, password|
  fill_in username: username
  fill_in password: password 
end

When 'I enter the bad credentials user: (\\S+) password: (\\S+) do |username, password|
  fill_in username: username
  fill_in password: password 
end

I strongly prefer the first approach, you should keep features and scenarios super simple and push complexity down to code. Code is much better at dealing with complexity than Cucumber.

I've been cuking since before Cucumber was named, and now never use regex's or scenario outlines when I cuke. You don't need to either.

Upvotes: 2

Please execute below step definitions and let us know if worked for you.

@When("^I enter the ([^\"]*) for the user$")
public void stepDefinition(String cred){
    //code
}
@When("^I enter the correct ([^\"]*) for the user$")
public void otherStepDefinition(String cred){
    //other code
}

Without Parameter

Feature File Steps implementation Output

With Parameter

enter image description here enter image description here enter image description here

Two metacharacters (^, $) are called anchors, because they’re used to tie down each end of the regular expression to the beginning and end of the string that they match on.

Upvotes: -1

Wiktor Stribiżew
Wiktor Stribiżew

Reputation: 626758

The first rule should be changed to

@When("I enter the (\\S+) for the user$")

Here, \S+ matches 1 or more non-whitespace characters. If there can be no non-whitespace chars use \S*.

To match two "words" you may use

@When("I enter the (\\S+\\s+\\S+) for the user$")

Note that you may control the number of "words" using quantifiers, e.g. this will match 2 or 3 words:

@When("I enter the (\\S+(?:\\s+\\S+){1,2}) for the user$")

To match 2 or more words:

@When("I enter the (\\S+(?:\\s+\\S+){1,}) for the user$")
@When("I enter the (\\S+(?:\\s+\\S+)+) for the user$")

Upvotes: 2

Related Questions