Supercharging Your Step Definitions

Everybody’s got a different way to say the same thing. When we create BDD scenarios, those style prose choices show up in the way we write.

This is great for adding flavor to every day language, but not so great when it means we have to write possibly duplicated code, just to handle a stylistic change.

So if one person would write:

When I click the submit button

And another one would write:

When I have clicked on the submit element

Then this could result in writing another step. But why?? They’re doing the exact same equivalent thing in the same manner.

Why Not Do Both?

A trick is to pepper step definitions with enough synonyms to allow multiple steps to hit the step definition. We can use regular expressions to expand the usefulness of our step definitions, resulting in a lot less time writing new code, just for handling cosmetic changes.

Here’s an example step definition, based on the above:

When(~/^I have clicked on the submit element$/)

Now let’s break it down:

Who is doing the clicking?

  • I
  • a user
  • the user
  • you

We may not care who’s doing the action, so we can wrap it in a non-capturing group, like this:

When(~/^(?:I|a user|the user|you) have clicked on the submit element$/)

Note the “?:” token at the beginning of the group. This is how to specify that the group is the non-capture variety.

A non-capture group just means we want this part of the regular expression to help with matching, but we’re not going to use it for anything else after that. It’s just a filter. There’s an example of a capturing group later on.

Next question: What tense are we using? Should we match on present or past tense? Who cares! Put them all in:

  • have clicked
  • has clicked
  • is clicking
  • just clicked

We again don’t really need to track this for later, so we can use a non-capturing group. And we can be a little more slick this time so we have a shorter step definition:

When(~/^(?:I|a user|the user|you) (?:have|has|is|just) click(?:ed|ing) on the submit element$/)

This covers all possible permutations, even wonky ones like “have clicking”. It just means that we can has the flexibility, and have a somewhat shorter step definition.

Then we look at the prepositional part of the step. We’d either say we click the or on the target element:

When(~/^(?:I|a user|the user|you) (?:have|has|is|just) click(?:ed|ing) (?:on the|the) submit element$/)

Next, we can wrap a non-capture group around the element type itself. For brevity we’ll just do the ones in the examples further up: element or button:

When(~/^(?:I|a user|the user|you) (?:have|has|is|just) click(?:ed|ing) (?:on the|the) submit (?:element|button)$/)

Finally, the one place we might care about enough to capture is the name of the element we’re acting on–submit. All we do for that is leave off the non-capture token, like this:

When(~/^(?:I|a user|the user|you) (?:have|has|is|just) click(?:ed|ing) (?:on the|the) (.*) (?:element|button)$/)

Increasing Readability

This step definition is getting pretty long. There’s another thing we can do that can help with readability, and that is: put the regular expressions in variables, and then embed the variables in the step definition itself.

And, we can… probably… you know what, let’s clean this up a little bit too and make the step readable even with variables stuck in there.

How about we make variables for the following regexes:

def theUser = "(?:I|a user|the user|you)"
def clicks = "(?:have clicked|has clicked|is clicking|just clicked|clicked)"
def onThe = "(?:the|on the)"
def element = "(?:element|button)"

And then splice in these variables in the step definition like this:

When(~/^${theUser} ${clicks} ${onThe} (.*) ${element}$/)

Very niiiiiiiiiice. Not only does this shorten up the step definition, but it’s still clear what the step is doing.

Would this help clean your automation code up somewhat? Decrease repetitive code, shorten maintenance and increase readability? Probably so.

Got any similar tips? (?:Leave|Drop) them (?:in|down in) the comments below!


Readability is one of the three pillars of good test automation–the other two being maintainability and extendability. If you haven’t mastered these pillars, don’t worry, because I know a consultancy that can help. I’ve known the president of the company for… wow, my whole life! He’s good people. 

Advertisements

3 thoughts on “Supercharging Your Step Definitions

  1. Thanks for sharing, very cool tips.

    PS: typo in your (?:last|final) step?
    It currently says “${element)$/”. I am expecting the closing curly bracket, not the round bracket. Please confirm.
    Like so: “${element}$/”

    Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s