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.
Related
Say we have a simple "concept" Car with those properties (using pseudocode, this question is language agnostic):
Car
{
string Brand;
string[] Tags;
}
Note that I have not said this is a class of code, nor this is a database object or anything... this is just a "concept" in our domain.
For this example we'll assume tags are free text, not selected from a closed-collection of tags like it happens in stack-overflow where the tags "refer" to the "real tag entity". In this example they are just strings over there.
Let's assume we are using a CQRS + Event Sourcing for this application so we will be able to track when the car was created, who edited it, etc.
Our first application requirements require us to "create cars" but not edit them. Naturally the creation event could easily be seen as:
CarCreated( string Brand, string[] Tags );
One month after, they request us to edit cars. They want to edit the brand and the tags.
Of course, the car edition of the brand or the tags is independent, and we could have 2 approaches here:
Approach 1) There are 2 events, one for each thing:
CarBrandEdited( [pass here the brand info] )
CarTagsEdited( [pass here the tags info] )
or
Approach 2) There is a single atomic edition event
that may touch one or the other or both:
CarEdited( [pass here the edition definition] )
Define one or the other approach I feel it's rather "domain-based"... You cannot change a date by changing its "day" and then its "month" as in between there is a micro-second gap where the date is incorrect.
Either it is "4th-jul" or "18th-aug" but never "18th-jul" as it would happen if we first update the day and later the month. This means "making those 2 changes atomic".
My question specifically arises around the TAGS thing...
If I have this set of tags for an object:
green kitcheeeen tall wood
and I give a form to a user and the user inputs:
green kitchen metal soft
How would I have to proceed?
Option a)
Tags edited, new tags = "green kitchen metal"
Option b)
Tag kitcheeeen removed
Tag tall removed
Tag wood removed
Tag kitchen added
Tag metal added
Tag soft added
Option c) (probably not doing a form, but giving the user crosses to remove and pencils to edit text)
Tag kitcheeeen changed for kitchen
Tag tall removed
Tag wood changed for metal
Tag soft added
I don't enter in the issue if those changes should be "atomic" all in one event or "spread" into seaparate events... What I'm interested in is:
For me option C is the one more purist and the one that conveys more "meaning" to the event... but that is an overkill in programming the user interface to allow the user distinguish if
a text-change is an edition (like wood for metal, as it seems a material change, probably the user would edit the tag in a box) or
a text-change is just a removal and a separate addition (like dropping tall and adding soft, probably the user would press a x on the tall and clicking + would have a blank textbox to enter a new tag.
Reinforce by the idea that tags are "meaning semantics", Option C seems "the one". But it's overkill in the front makes me thing if I'm missing a good-albeit-simpler solution.
How should the CarEdited event be defined?
In my opinion it depends on the question: "does tracking this brings business value?"
If you see business value in knowing if the user edited a tag directly or by deleting/rewriting it, if you believe you will need to know this in the future, then option C is the way to go.
But in most cases it's perfectly fine to just store the event CarEdited { newBrand, newTags }.
Side notes:
I never used that but I read that it's useful to have reversible events, maybe you want to store the event CarEdited { oldBrand, newBrand, oldTags, newTags }.
Also, one great thing about Event Sourcing is that it emancipates you from CRUD language and replace it by business language. I guess your user didn't create the car, they just registered it in your system, maybe you want to call the first event CarRegistered instead of CarCreated.
Hope this helps!
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
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.
I am new at the idea of programming algorithms. I can work with simplistic ideas, but my current project requires that I create something a bit more complicated.
I'm trying to create a categorization system based on keywords and subsets of 'general' categories that filter down into more detailed categories that requires as little work as possible from the user.
I.E.
Sports >> Baseball >> Pitching >> Nolan Ryan
So, if a user decides they want to talk about "Baseball" and they filter the search, I would like to also include 'Sports"
User enters: "baseball"
User is then taken to Sports >> Baseball
Now I understand that this would be impossible without a living - breathing dynamic program that connects those two categories in some way. It would also require 'some' user input initially, and many more inputs throughout the lifetime of the software in order to maintain it and keep it up to date.
But Alas, asking for such an algorithm would be frivolous without detailing very concrete specifics about what I'm trying to do. And i'm not trying to ask for a hand out.
Instead, I am curious if people are aware of similar systems that have already been implemented and if there is documentation out there describing how it has been done. Or even some real life examples of your own projects.
In short, I have a 'plan' but it requires more user input than I really want. I feel getting more info on the subject would be the best course of action before jumping head first into developing this program.
Thanks
IMHO It isn't as hard as you think. What you want is called Tagging and you can do it Automatically just by setting the correlation between tags (i.e. a Tag can have its meaningful information plus its reation with other ones. Then, if user select a Tag well, you related that with others via looking your ADT collection (can be as simple as an array).
Tag:
Sport
Related Tags
Football
Soccer
...
I'm hoping this helps!
It sounds like what you want to do is create a tree/menu structure, and then be able to rapidly retrieve the "breadcrumb" for any given key in the tree.
Here's what I would think:
Create the tree with all the branches. It's okay if you want branches to share keys - as long as you can give the user a "choice" of "Multiple found, please choose which one... ?"
For every key in the tree, generate the breadcrumb. This is time-consuming, and if the tree is very large and updating regularly then it may be something better done offline, in the cloud, or via hadoop, etc.
Store the key and the breadcrumb in a key/value store such as redis, or in memory/cached as desired. You'll want every value to have an array if you want to share keys across categories/branches.
When the user selects a key - the key is looked up in the store, and if the resulting value contains only one match, then you simply construct the breadcrumb to take the user where you want them to go. If it has multiple, you give them a choice.
I would even say, if you need something more organic, say a user can create "new topic" dynamically from anywhere else, then you might want to not use a tree at all after the initial import - instead just update your key/value store in real-time.
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)