Monday, December 28, 2015

Writing Cucumber JVM step definitions

Below are some I found the most useful.
Exact match
I know it’s a no-brainer but will get you started.
@Given("I have a cucumber step")
public void i_have_a_cucumber_step() throws Throwable {
    System.out.println("Step definition exact match");
}

Use anchors

Remember to use anchors to mark the beginning (^) and end of the expression ($). The step definition above will match both steps below:
Given I have a cucumber step
Given I have a cucumber step and a salad
What we really want is to match the first one and get Cucumber to give us a stub implementation of the second one. In order to avoid unexpected matches we need to add anchors:
@Given("^I have a cucumber step$")
Capture integers and strings
@Given("^I have (\\d+) (.*) in my basket$")
public void i_have_in_my_basket(int number, String veg) throwsThrowable {
    System.out.println(format("I have {0} {1} in my basket", number, veg));
}
Let’s have a look at the step definition. By using round brackets we mark part of the expression as a capture group so that Cucumber can map it to a method parameter. In our case have the following patterns:
  • \d+ matching at least one digit, d represents a digit, + is a quantifier and means one or more times; the expression is escaped with a backslash, because it also is the escape character in Java we need to escape it with another backslash and we end up with \\d+
  • .+ matching at least one character, . (dot) represents any character
Singular and plural
Use ? qualifier to match words in both singular and plural. ? at the end of a word makes the last letter optional. We can also use the logical alternative operator |(pipe) to support correct grammar as well as irregular plurals which will make sentence read better.
@Given("^There (?:is|are) (\\d+) (?:cats?|ox|oxen) fed by (\\d+) (?:persons?|people)$")
public void animals_fed_by_people(int animals, int persons) throwsThrowable {
    System.out.println(
            format("{0} animal(s) fed by {1} person(s)", animals, persons));
}
Given There is 1 cat fed by 1 person
Given There are 2 cats fed by 1 person
Given There are 2 cats fed by 2 persons
Given There are 2 cats fed by 3 people
Given There is 1 ox fed by 4 persons
Given There are 3 oxen fed by 5 people


Use Data Tables

You can use DataTable to manage larger amount of data. They are quite powerful but not the most intuitive as you either need to deal with a list of maps or a map of lists.
@Given ("^I have the following order$")
public void i_have_the_following_order (DataTable table) throwsThrowable {
    for (Map<String, String> map : table.asMaps(String.class, String.class)) {
        String vegetable = map.get("vegetable");
        String amount = map.get("amount");
        String cost = map.get("cost");
        System.out.println(
                format("Order of {0} {1}s at the cost of {2}",
                amount, vegetable, cost));
    }
}
Scenario: Data tables
  Given I have the following order
    | vegetable | amount | cost |
    | cucumber  |   4    |  10  |
    | carrot    |   5    |   6  |
    | potato    |   6    |   4  |
For Cucumber Regular Expressions Cheat Sheet visit on Cucumber Regular Expressions Cheat Sheet

Best practices when creating your Step Definitions (or really any Glue Code).
  • The matcher is not overly verbose
  • The matcher handles both positive and negative (true and false) conditions
  • The matcher has at most two value parameters
  • The parameter variables are clearly named
  • The body is less than fifteen lines of code
  • The body does not call other steps

Different types of steps:

Successful steps

When Cucumber finds a matching Step Definition it will execute it. If the block in the step definition doesn’t raise an Exception, the step is marked as successful (green). What you return from a Step Definition has no significance what so ever.
Undefined steps

When Cucumber can’t find a matching Step Definition the step gets marked as yellow, and all subsequent steps in the scenario are skipped. If you use --strict this will cause Cucumber to exit with 1.

Pending steps

When a Step Definition’s Proc invokes the pending method, the step is marked as yellow (as with undefined ones), reminding you that you have work to do. If you use --strict this will cause Cucumber to exit with 1.

Failed steps

When a Step Definition’s Proc is executed and raises an error, the step is marked as red. What you return from a Step Definition has no significance what so ever. Returning nil or false will not cause a step definition to fail.

Skipped steps

Steps that follow undefined, pending or failed steps are never executed (even if there is a matching Step Definition), and are marked cyan.


No comments:

Post a Comment