Cucumber is a very vibrant eco-system on it's own. It became the defacto-standard tool for high-level testing and a great addition to the Behavior Driven Development set of tools. I'm sharing with you a list of tips related to it.
I thank this has become so common-practice, and I totally advocate the decision of removing web_steps.rb
. As you go to the roots of the process itself, it's all meant to be described in a language that's both familiar to your end users and yourself, but also uses dead simple domain terms, as in a token for a conversation.
A good written feature might be written like this.
Scenario: User subscribes to category
Given a User exists
And is logged in
When he subscribes to the "Programming" category
Then he should see the posts listed on that category
Perhaps it suffers from a little global abuse but it seems to me that the readability gains outperform that. In order to get the most of this fairly simple feature, and to get the overall picture, you need to understand that:
Your actions should be unique. They should be easily distinguishable from any other actions, and they shouldn't be ambiguous. Don't do this, although it might seem pretty trivial.
When /I (order|buy) (.+)/ do |item|
# ...
end
Although the flexibility might temp you, it'll hurt you later. You're to be expected to have clarity and unambiguity in your feature files.
Table diffs are a great feature. Just get in mind don't to over-use them. When you're comparing it seems that you can add to readability by cutting the clutter and writing the right step definition.
Background:
Given the following Products:
| name | price | description |
| Socks | 5.00 | ... |
| Cap | 3.00 | ... |
# ...
Scenario: Buying Products
# ...
When I buy a "Cap"
And I buy a pair of "Socks"
Then my shopping list should contain:
| Socks |
| Cap |
Adjust your table diffs to use and compare only relevant information. We don't care about the price and description in the shopping list, we only want to verify the products are there.
As an aside, it would be really nice if we can avoid the need to prevent repeating the action and do some chain step defining, but it would be strange or abused, I mean I guess there is a good reason this hasn't been implemented. I'm talking about something like this:
# ... Same as before
When I buy a "Cap"
And a pair of "Socks"
# ...
Chain the "buy a..." step definition. What do you think?
This is one of the nicest features added to Cucumber. It allows you to avoid the need of repeating the same data transformation from scenario to step definition and instead defining those in a single place. Of course, it could be abused as everything in life, but it's still a life-saver on it's own right. This simple example it's perhaps the most common example found in my code:
Transform /^\d+/ do |number|
number.to_i
end
Then, on the step definition (Look mom, no to_i
!)
Then /^I should have (\d+) pets/ do |count|
Pets.count.should == count
end
Tagged hooks are a great feature that allows you to run custom code before and after a tagged scenario. It builds upon the normal Before
and After
hooks, but now you can use tags with it.
This helps avoiding global abuse and code duplication, along with the added readability.
Suppose you need to perform certain actions if the scenario is for an administrator. You don't want to repeat those actions, and you don't want to call that helper method on every feature/scenario, right?
In the scenario, just a tag away:
@admin
Scenario: Whatever you want
And you define the tagged hook:
Before('@admin') do
user = Factory.create(:admin)
login(user)
end
Clean and concise.
Cucumber tags are so great that I couldn't help by mentioning them. You should try to use that as much as it makes sense. Subfolders too. Don't try to put everything in a single place when you're only a require features
away.
Get comfortable with the @wip
tag.
Integrate your team's workflow with tags as well.
Nest steps carefully, in preference don't nest them at all. Nesting comes with coupling and there are good chances that the benefits are not that huge.
Choosing branch names and feature file names is entirely up to you. I use, as many, prefixed feature branches. Setting up your branches name to be as closely as possible to the feature you're working on, and the filename when the feature is described it's a very helpful initiative.
Examples:
Branch: feature/commenting, Feature: features/commenting.feature
Branch: feature/profile-notifications, Feature: features/profile/notifications.feature
Use guard-cucumber
to run your features for you. Features are slow, I know, but you should do this anyways. It's pretty annoying having your features running that many times, so what about using the Gem and pausing the file modification from time to time? I work this way and I
run my entire suite on every "Pomodoro" break.
No, I'm not telling you how to use PrintScreen or Shutter ;)
Besides the known HTML reports, it came to me somewhere that you can actually take screenshot of your scenarios involving javascript. This is a really neat feature for reports (people love visuals), but specially for debugging.
After('@javascript') do |scenario|
if scenario.failed?
page.driver.browser.save_screenshot("html/#{scenario.__id__}.png")
embed("#{scenario.__id__}.png", "image/png", "SCREENSHOT")
end
end
That's it. Just a quick list of 10 tips you might heard (or not) about.
Did you think about other interesting tips while you were reading?
Cool, add a comment on them.