We are trying to incorporate CSV into Cucumber to get the benefit of CSV files, but when researching online I see no official documentation on this feature but only "Import scenario outline 'examples' from CSV?".
I am not sure if this comes to any conclusions yet. Is it currently any built-in way to use CSV in Cucumber?
If currently there is no built-in way to import CSV, and I have to write the own parsing method, I think my question will be, in the step definition, how do I hook up the variables with the definition in scenario? For example:
Scenario: do something
Given I eat number as <number> cucumbers
and the cucumber is produced at date as <date>
When the cucumber is expired
Then I should have diarrhea
data.csv
number,date
1,2012-01-01
1,2012-11-03
in the steps.rb, if I do:
CSV.foreach("path/to/data.csv") do |row|
...
How to I map row.number`row.date` to the number\date in the feature file?
In order to use the Examples functionality in cucumber I think you'd have to do some significant metaprogramming that would probably reduce the maintainability and readability of your features. I'd probably accomplish this by wrapping you current steps in another step definition like so:
Scenario: do something
Given I load some data
Then expired cucumbers should give me diarrhea
and the define the step definitions
Then 'I load some data' do
#data = []
CSV.foreach("path/to/data.csv", headers: true) do |row|
#data << row
end
end
Then 'expired cucumbers should give me diarrhea' do
#data.each do |row|
step %Q|I eat number as #{row[:number]} cucumbers|
step %Q|the cucumber is produced at date as #{row[:date]}|
step %Q|the cucumber is expired|
setp %Q|I should have diarrhea|
end
end
The only problem with this is that if one scenario fails, it may take an extra debugging step to figure out which one is failing. Since these steps are run, more or less, under the hood. You could do this pretty easily by printing the row to STDOUT from the step definition:
Then 'expired cucumbers should give me diarrhea' do
#data.each do |row|
puts "row", row.inspect
step %Q|I eat number as #{row[:number]} cucumbers|
step %Q|the cucumber is produced at date as #{row[:date]}|
step %Q|the cucumber is expired|
setp %Q|I should have diarrhea|
end
end
That should give you some indication of which row is giving you trouble.
Erata: I understand your desire to be able to maintain a data sheet separate from the features so that someone like a Project Manager can come up with edge cases and then have those run against the behavior of the code. But I'd almost be more willing to allow them to edit the feature on github and allow CI to run those examples they added to the example table rather than do this approach. In either case its probably something good for regression, but probably really painful to develop code against. This type of testing is sort of the aim of http://fitnesse.org/ and that might be a project of inspiration for you.
Related
I have a feature file A with 8-9 lines of steps which is covering one scenario. Now I need to use feature file A as a background step in feature file B by reducing number of steps to 3-4.
My approach:
In feature file B - Reduce steps(from feature file A) to 3-4 lines, use helper methods and add as background steps.
Feature file A:
Feature: I want to create an event
Background: User is Logged In
Given a logged in user
Scenario: Creating an event
Given I select event
And I add event details
And I add start and end time
Then Timings will be added successfully
When I add ticket information and continue
And Publish my event
Then I verify event will be created successfully
Feature file B
Feature: Place an order
Background: Event is created
Given a logged in user
When I select event and fill in required details
Then event should be published
I'm concern about duplication. I'm using feature file A as a background step in feature file B by reducing number of steps but functionally both feature files are testing same feature.
Please suggest a better approach if possible. Thank you
So fundamentally using helper methods to reduce number of steps is only something you should do if the compressed steps are also conveying the information correctly. So here is an example (You don't need helpers here either), that would be a good use case.
Given I have a party of 2/1/0 # This means adults/children/infants
And the child is under 12
And I am flexible on my flights
And I am going to Spain
When I search for flights
Given I have Spanish flights displayed # You could also add the pax in here if you wanted
Now if you're wanting to use helper methods, that is also fine, but you need to remember cucumber is primarily a tool for encouraging collaboration as well as providing documentation, testing and specification in the same place. So once you try to DRY up your lines, think about whether actually you just want to "compress" the lines down.
i.e.
Given('I am {int} years old') do |age|
#person.age = age
end
Given('my name is {word}') |name|
#person.name = name
end
Given('my hometown is {string}') |hometown|
#person.location = hometown
end
Can become
Given('I am {word}, {int} years old from {string}') |name, age, hometown|
#person.name = name
#person.age = age
#person.location = hometown
end
Hopefully some of these tips will have given you some thought.
I have two cucumber feature ( DeleteAccountingYear.feature and AddAccountingYear.feature).
How can i do to make that the second feature(AddAccountingYear.feature) run before the first one (AddAccountingYear.feature).
I concur with #alannichols about tests being independent of each other. Thats a fundamental aspect of automation suite. Otherwise we will end up with a unmaintainable, flaky test suite.
To run a certain feature file before running another feature appears to me like a test design issue.
Cucumber provides few options to solve issues like this:
a) Is DeleteAccountingYear.feature really a feature of its own? If not you can use the cucumber Background: option. The steps provided in the background will be run for each scenario in that feature file. So your AddAccountingYear.feature will look like this:
Feature: AddingAccountingYear
Background:
Given I have deleted accounting year
Scenario Outline: add new accounting year
Then I add new account year
b) If DeleteAccountingYear.feature is indeed a feature of its own and needs to be in its own feature file, then you can use setup and teardown functions. In cucumber this can be achieved using hooks. You can tag AddDeleteAccountingYear.feature with a certain tag say #doAfterDeleteAccountYear. Now from the Before hooks you can do the required setup for this specific tag. The before hooks(for ruby) will look like:
Before('#doAfterDeleteAccountYear') do
#Call the function to delete the account year
end
If the delete account year is written as a function, then the only thing required is to call this method in the before hook. This way the code will be DRY compliant as well.
If these options doesn't work for you, one another way of forcing the order of execution is by using a batch/shell script. You can add individual cucumber commands for each feature in the order you would like to execute and then just execute the script. The downside of it is different reports will be generated for each feature file. But this is something that I wouldn't recommend for the reasons mentioned above.
From Justin Ko's website - https://jkotests.wordpress.com/2013/08/22/specify-execution-order-of-cucumber-features/ the run order is determined in the following way:
Alphabetically by feature file directory
Alphabetically by feature file name
Order of scenarios within the feature file
So to run one feature before the other you could change the name of the feature file or put it in a separate feature folder with a name that alphabetically first.
However, it is good practice to make all of your tests independent of one another. One of the easiest way to do this is to use mocks to create your data (i.e. the date you want to delete), but that isn't always an option. Another way would be to create the data you want to delete in the set up of the delete tests. The downside to doing this is that it's a duplication of effort, but it won't matter what order the tests run in. This may not be an issue now, but with a larger test suite and/or multiple coders using the test repo it may be difficult to maintain the test ordering based solely on alphabetical sorting.
Another option would be to combine the add and delete tests. This goes against the general rule that one test should test one thing but is often a pragmatic approach if your tests take a long time to run and adding the add data step to the set up for delete would add a lot of time to your test suite.
Edit: After reading that link to Justin Ko's site you can specify the features that are run when you run cucumber, and it will run them in the order that you give. For any that you don't care about the order for you can just put the whole feature folder at the end and cucumber will run through them, skipping any that have already been run. Copy paste example from the link above -
cucumber features\folder2\another.feature features\folder1\some.feature features
I've set screenshots to be taken when a scenario fails, but my html report shows the same screenshot on all failed scenarios. Can anyone help and let me know how I can get unique screenshots taken for each failed scenario.
Here is my code in my env.rb:
After do |scenario|
if scenario.failed?
#browser.driver.save_screenshot("screenshot.png")
embed("screenshot.png", "image/png")
end
You are saving the screenshot to the same file each time (ie overwriting the previous screenshot each time). The report has also linked all the images to the same place. This is why you get the same image everywhere.
You need to provide a unique name for the screenshot.
For example, you could timestamp (with date and time) the images:
After do |scenario|
if scenario.failed?
screenshot_file = "screenshot-#{Time.now.strftime('%Y%m%d-%H%M%S')}.png"
#browser.driver.save_screenshot(screenshot_file)
embed(screenshot_file, "image/png")
end
end
Justin has the answer, But while timestamps are fine, they make it harder when looking at the files to know which one was for what scenario. When I run tests while creating and debugging, I often don't even look at the html report, I just look at the generated screenshot, so in that case it is doubly useful to have more logical names.
So the code I use looks like this, and embeds using the scenario name
After do |scenario|
if scenario.failed?
screenshot = "./FAILED_#{scenario.name.gsub(' ','_').gsub(/[^0-9A-Za-z_]/, '')}.png"
#browser.driver.save_screenshot(screenshot)
encoded_img = #browser.driver.screenshot_as(:base64)
embed("data:image/png;base64,#{encoded_img}",'image/png')
end
end
An even more robust approach, dealing with scenario outlines and appending timestamp is described in this 'Two Four One' blog posting so far I've not needed to go that far, but I may pull in stuff from it to deal with scenario outlines.
for the ones using RSpec, there is a really nice implementation of HtmlFormatter in the watir-rspec project
I wrote a feature to test the default configuration of my web app using Cucumber and Capybara. Part of the feature looked like this:
And the page has a photo labeled "Device"
And the page has a checkbox labeled "Device"
And I check "Device"
And I submit the form
Then the resulting page has no photo labeled "Device"
It worked great. I want users who have installed and configured the web app on their own servers to be able to run the test to help confirm that their configuration is correct. And "Device" is a string in the default config file that the user can change. It's an element in an array and they can add to or remove from the array when configuring their instance of the app.
Is this a sensible use of the tools or am I abusing Cucumber and/or Capybara? If it's sensible, how would I do it? If it's a bad idea, what tools might I use for this instead, if anything?
Here's how I got it to work. I'm just not sure this is the best way to do it.
For this to work, the feature would have to look more like this:
And the page has at least 3 photos, let us call the last one "third_photo"
In the corresponding step definition, I use an XPath to pull out the corresponding label string for the first photo and assign it to a Hash object stored in a class variable.
And /^I the page has at least (\d*) photos, let us call the last one "([^\"]*)"$/ do |n, name|
if ! defined?(#note)
#note = Hash.new;
end
#note[name] = find(:xpath, '//ol[#id="menu"]/li[' +n+ ']/a').text;
end
Subsequent step definitions can now access the value, whatever it was.
So, another feature might be:
Then I uncheck "third_item"
And the corresponding step definition might be:
Then /I uncheck "([^\"]*)"/ do |item|
uncheck(#note[item])
end
But I don't feel good about it. If nothing else, I imagine there might be a name collision with another instance variable defined outside the step definitions.
It feels like I'm either Doing It Wrong or else I'm Using The Wrong Tool. What is the right way to do this?
Don't know what you are fishing after, but it feels like your tests and implementation are quite tightly coupled. Maybe that's the feeling you are having, that it seems like you are describing your app in tests.
I don't have a good answer to your questions, merely because I don't "understand" it. I would however urge you to try to decouple your tests from your implementation and see if there's any abstraction there waiting to be found.
There's a blog post about using instance variables in step definitions at http://www.cloudspace.com/blog/2010/06/23/using-instance-variables-with-cucumber-steps/.
Commenters talk about the coupling this entails and at least one possible way around it.
In particular, davetron5000 says:
What we do is to not use instance variables at all, but instead
provide a has that shared state can go in. This hash is cleared after
each test run. Not ideal, but it's a bit cleaner than random instance
variables all over the place (and also ensures a reasonably clean
state before each test)
When i run cucumber it displays the
possible steps that i should define, an example from the RSpec book:
1 scenario (1 undefined)
4 steps (4 undefined)
0m0.001s
You can implement step definitions for undefined steps with these snippets:
Given /^I am not yet playing$/ do
pending
end
When /^I start a new game$/ do
pending
end
Then /^the game should say “Welcome to CodeBreaker”$/ do
pending
end
Then /^the game should say “Enter guess:”$/ do
pending
end
Is there a way that it will automaticly create the step definitions file, so i don't have to
rewrite or copy paste by hand but i can just to customize them to be more generic?
Cucumber doesn't offer this feature. Probably because you would have to tell it where to put the step definitions file, and what to name it.
Like Kevin said, Cucumber would have to know the name of the file to put it in, and there are no good defaults to go with, other than using the same file name as the feature file. And that is something I consider an antipattern: http://wiki.github.com/aslakhellesoy/cucumber/feature-coupled-steps-antipattern
Intellij Idea or RubyIDE does exactly what you are asking for:
Detects missing step definitions
Creates missing step definitions in a new file (you choose the name of the file) or in one of the existing step definition files
Highlights matched step parameters
see http://i48.tinypic.com/10r63o4.gif for a step by step picture
Enjoy
There is a possibility this kind of feature could be useful, but as Kevin says, it doesn't exist at present. But it could also get quite messy, quite quickly.
Maybe you already do this, but there's nothing stopping you cut and pasting the output direct into your text editor, or even piping the output direct to your text editor if you're so inclined. Then at least you're getting pretty much most of the way there, bar creating the file and naming.
try this https://github.com/unxusr/kiwi it auto generate your feature file and make the step definitions file for you and you just fill in the steps with code.
In later version will write the code of the steps and run the test all of that automagically
You can use a work around way to generate steps file
all you have to do is to run the Cucumber on a feature doesn't have defined steps by identify a specific feature as the following command:
1) using path
bundle exec cucumber {PATH}
note path would start with features/....
for example
features/users/login.feature
1) using tags
bundle exec cucumber --tags=#{TAG}
note tag should be above your scenario in the steps file
for example
#TAG
Scenario:
And you will have the suggested steps in the console with pending status