In my previous post I started to play around with cucumber-jvm to see how it could be used for Java development. Last time I finished with one scenario and now I’m going to move forward with my simple text munger implementation and see how to use cucumber-jvm with multiple scenarios.
Before doing anything, I installed infinitest so that I didn’t have run the test cases manually. This really sped up the development. I recommend you to do the same.
I filled out my steps, did a bit of implementation and now this is how the steps look like:
Quick Detour - Playing Around With Step Definitions
The ruby version of cucumber is quite flexible. For example, Given
, When
and Then
are not bound to the step definitions, so the following works - simple_text_munger.feature
:
Feature: simple text munger kata
Scenario: Do nothing with a two-letter word
Then I have an instance of my class
Given I call my method with "an"
When I receive "an"
The good news is that it also works with cucumber-jvm, and there is more! Sometimes you have to give multiple steps with the same Given
, When
and Then
prefix. In this case you can use the And
prefix. So instead of multiple Thens
in simple_text_munger.feature
:
Feature: simple text munger kata
Scenario: Do nothing with a two-letter word
Then I have an instance of my class
Then I call my method with "an"
Then I receive "an"
Use one Then
with several Ands
:
Feature: simple text munger kata
Scenario: Do nothing with a two-letter word
Then I have an instance of my class
And I call my method with "an"
And I receive "an"
These formats are ugly and I don’t recommend using them, but the goal of my posts is to show the capabilities of cucumber-jvm, and so far it has all the features the ruby version has.
The Next Scenarios
It’s time to return to the subject at hand and move forward with my implementation. My modified text munger kata says that* the first and the last letter of a word should be kept and the letters in between need to be reversed.* I have one scenario so far, where I check how my implementation behaves with a two-letter word. So let’s have two more scenarios in the simple_text_munger.feature
:
Feature: simple text munger kata
Scenario: Do nothing with a one-letter word
Given I have an instance of my class
When I call my method with "a"
Then I receive "a"
Scenario: Do nothing with a two-letter word
Given I have an instance of my class
When I call my method with "an"
Then I receive "an"
Scenario: Do nothing with a three-letter word
Given I have an instance of my class
When I call my method with "and"
Then I receive "and"
Nothing else needs to be changed, because I’m still all green:
Refactoring the Feature File
If you check the scenarios above, they are almost the same, only the in and out parameters differ. This is not DRY, so let’s refactor a little bit. After moving the first step into Background
- which is executed before each scenario -, our .feature
file - simple_text_munger.feature
- looks like this:
Feature: simple text munger kata
Background:
Given I have an instance of my class
Scenario: Do nothing with a one-letter word
When I call my method with "a"
Then I receive "a"
Scenario: Do nothing with a two-letter word
When I call my method with "an"
Then I receive "an"
Scenario: Do nothing with a three-letter word
When I call my method with "and"
Then I receive "and"
Looks a bit better, but I’m still not one hundred percent satisfied: the scenarios are the same except the parameters they have. The ruby version of cucumber has a very powerful feature called Scenario Outline. This is how I would refactor the scenarios above using this feature:
Feature: simple text munger kata
Background:
Given I have an instance of my class
Scenario Outline: Do nothing with words shorter than 4 letters
When I call my method with <input>
Then I receive <output>
Examples:
| input | output |
| "a" | "a" |
| "an" | "an" |
| "and" | "and" |
And this works just as well with cucumber-jvm:
The table structure from above is also commonly used like this:
Scenario: do something interesting
Given the following users
| first_name | last_name |
| John | Doe |
| Jane | Doe |
And the matching step implementation in Java:
package com.zsoltfabok.blog;
import java.util.List;
import cucumber.annotation.en.Given;
public class SomeOtherStepsdef {
@Given("^the following users$")
public void the_following_users(List<entry> entries) {
// iterate through the list and do something
}
class Entry {
String first_name;
String last_name;
}
}
Fortunately, it works just as well with cucumber-jvm. I don’t see a chance to use it with the current example, but I wanted to try it out anyway and see whether it works.
Finishing the Word Processing
The last scenario is when a word has 4 or more letters:
Scenario Outline: It should munger a word properly
When I call my method with <input>
Then I receive <output>
Examples:
| input | output |
| "a" | "a" |
| "an" | "an" |
| "and" | "and" |
| "spice" | "scipe" |
I got a red bar:
With the following Java code I get all green:
At this point my implementation works with a single word, but the exercise requires a sentence as an input. Let’s add a new scenario to the .feature
file:
Scenario: It should process a sentence
When I call my method with "And the spice must flow"
Then I receive "And the scipe msut folw"
I really like what I’ve seen so far, everything I’m using with cucumber for ruby works with cucumber-jvm too, but a wise man told me once that I should go home with a red test case, because it will show me where I finished my work yesterday. You can find the source for this post under the episode_2 branch of the repository on github. Now, I have a red test case which I’m going to fix it in the next post, where besides the fix I’m going to show how cucumber-jvm works with dependency injection frameworks. Stay tuned!
comments powered by Disqus