Having a problem with making this work. Seems it has been a problem for others and I think I have followed all of the advice.
I've set up a stripped down rails 3 .0.14 app to just include cucumber-rails & factory_girl_rails but still no go. I expect I am doing something silly!
Running the cuc test below produces the following:
Scenario: test factory-girl # features/users.feature:3
Given the following user exists: # features/users.feature:4
| name | email |
| Brandon | brandon#example.com |
Undefined step: "the following user exists:" (Cucumber::Undefined)
The user factory has been created, of which I am sure, with a bit of 'pp' output.
Would really appreciate any help to get this sorted.
Ross
Set up
env.rb: snippet
require 'pp'
require 'cucumber/rails'
require 'factory_girl_rails'
require 'factory_girl/step_definitions'
features/support/factories.rb:
FactoryGirl.define do
factory :user do
name 'Adam Advertiser'
email 'a#b.com'still
end
end
pp FactoryGirl.create(:user)
Cucumber features/user.feature:
Feature: a
Scenario: test factory-girl
Given the following user exists:
| name | email |
| Brandon | brandon#example.com |
The problem here is that you have to get your factory required before requiring 'factory_girl/step_definitions', because there is meta-programming in step_definitions which needs to know about your factory. You could explicitly require the factories.rb in the env.rb, but that will end up producing a duplicate definition error, as cucumber will re-require factories.rb.
You need to remove the requiring of step_definitions from the env.rb - that will make it happen too early - and put it at the bottom of factories.rb, or else create a wrapper which requires first the factories (which will need to reside somewhere that cucumber doesn't automatically require) and then the step_definitions.
Related
I have the following scenario outline and I am generating allure report, But in the report we are not getting all the scenarios data, its showing only last run data.
It is showing only | uat1_nam | Password01 | test data result
Jenkins plugin version i am using is 2.13.6
Scenario Outline: Find a transaction based on different criteria and view the details
Given I am login to application with user "<user id>" and password "<password>"
When I navigate to Balances & Statements -> Find a transaction
Then I assert I am on screen Balances & Statements -> Find a transaction -> Find a transaction
#UAT1
Examples:
| user id | password |
| uat1_moz | Password01 |
| uat1_nam | Password01 |
I got a similar issue.
We are running test with the same software on Linux and Windows, and generating results into 2 separate folders.
Then we have:
allure-reports
|_ linux_report
|_ windows_report
Then we are using the following command in the Jenkinsfile:
allure([
includeProperties: false,
jdk: '',
properties: [],
reportBuildPolicy: 'ALWAYS',
results: [[path: 'allure-reports/linux-report'], [path: 'allure-reports/windows-report']]
])
Similar to Sarath, only the results of the from the last run are available...
I also tried to run the cli directly on my machine, same results.
allure serve allure-reports/linux-report allure-reports/windows-report
I already found many methods, actually this one is very similar to my use case, but I do not understand why it works here, and not for me...
https://github.com/allure-framework/allure2/issues/1051
I also tried with the following method, but the Docker container is not running properly on Linux, due to permission issues... But I am running the container from a folder where I got all permissions. Same results if I give my userID in parameters:
https://github.com/fescobar/allure-docker-service#MULTIPLE-PROJECTS---REMOTE-REPORTS
I was able to get deeper into the topic, and I am finally able to prove why the data are overwritten.
I used a very simple example to generate 2 different reports, where only allure.epic was different.
As I thought, if we generate 2 different reports, with the same source folder, but generate 2 separate reports, then only the latest report will be considered (allure.epic name was updated in between).
If I have 2 different folders, with the same code (but only the allure.epic is different), then I have the all data available, and stored in different Suites!
Then, to make sure that allure considers the reports as different, and make a different classification for each OS, we have to make tests on code which is stored in different locations. Which does not fit with my usecase, as the same code is tested on both Linux and Windows.
Or maybe is there an option for pytest-allure to specify the root classification?
So my team is driving out our rails app (a survey and lite electronic record system) using Cucumber, Rspec and all the gems necessary to use these testing frameworks. I am in the process of setting up a Jenkins CI server and wanted to standardize our databases across our testing, development, and staging environments (we ended up choosing MySQL).
Upon switching the testing environment from SQlite to MySQL we discovered a couple of caching-related testing bugs that we resolved by using relative ids instead of hard-coded ones. example:
describe "#instance_method" do
before(:each) do
#survey = FactoryGirl.create(:survey)
#question_1 = FactoryGirl.create(:question)
#question_2 = FactoryGirl.create(:question)
....
end
context "question has no requirements" do
it "should match" do
# below breaks under MySQL (and postgres), but not SQlite
expect { #survey.present_question?(2) }.to be_true
# always works
expect { #survey.present_question?(#question_2.id) }.to be_true
end
end
end
After resolving this one failing spec, I addressed some unrelated ajax issues that have forever plaguing our test suite. Thinking that I finally masted the art of testing, I confidently ran rake. I was met with this unfriendly sight:
Now of course cucumber features/presenting_default_questions.feature rains green when ran in isolation.
Failing Scenario:
#javascript
Feature: Dynamic Presentation of Questions
In order to only answer questions that are relevant considering previously answered questions
As a patient
I want to not be presented questions that illogical given my previously answered question on the survey
Scenario: Answering a question that does not depend on any other questions
Given I have the following questions:
| prompt | datatype | options | parent_id | requirement |
| Do you like cars? | bool | | | |
| Do you like fruit? | bool | | | |
When I visit the patient sign in page
And I fill out the form with the name "Jim Dog", date of birth "1978-03-30", and gender "male"
And I accept the waiver
Then I should see the question "Do you like cars"
When I respond to the boolean question with "Yes"
Then I should see the question "Do you like fruit?"
When I respond to the boolean question with "No"
Given I wait for the ajax request to finish
Then I should be on the results page
Relevant step:
Then(/^I should be on the results page$/) do
# fails under ``rake`` passes when run in isolation
current_path.should == results_survey_path(1)
end
Then(/^I should be on the results page$/) do
# passes in isolation and under ``rake``
current_path.should == results_survey_path(Survey.last.id)
end
Besides from using Capybara.javascript_driver = :webkit, the cucumber / database cleaner config is unmodified from rails g cucumber:install.
It seems like both the failing rspec and cucumber tests suffer from the same sort of indexing problem. While the solution proposed above works, it's super janky and begs the question as to why a simple absolute index doesn't work (after all the database is cleaned between each scenario and feature). Is there something up with my tests? With database_cleaner?
Please let me know if more code would be helpful!
Relavent gem versions:
activemodel (3.2.14)
cucumber (1.3.6)
cucumber-rails (1.3.1)
database_cleaner (1.0.1)
capybara (2.1.0)
capybara-webkit (1.0.0)
mysql2 (0.3.13)
rspec (2.13.0)
The problem seems to be that you are missing the database_cleaner code for your Cucumber scenarios.
You mentioned that you have the database_cleaner code for your RSpec scenarios, but it seems that you're missing something like this for Cucumber's env.rb:
begin
require 'database_cleaner'
require 'database_cleaner/cucumber'
DatabaseCleaner.strategy = :truncation
rescue NameError
raise "You need to add database_cleaner to your Gemfile (in the :test group) if you wish to use it."
end
Around do |scenario, block|
DatabaseCleaner.cleaning(&block)
end
Do you have this code in there?
Can someone explain the difference between these two platforms?
Are both part of BDD but why should I use one or other, or both together?
Capybara is a tool that interacts with a website the way a human would (like visiting a url, clicking a link, typing text into a form and submitting it). It is used to emulate a user's flow through a website. With Capybara you can write something like this:
describe "the signup process", :type => :feature do
before :each do
User.make(:email => 'user#example.com', :password => 'caplin')
end
it "signs me in" do
visit '/sessions/new'
within("#session") do
fill_in 'Login', :with => 'user#example.com'
fill_in 'Password', :with => 'password'
end
click_link 'Sign in'
page.should have_content 'Success'
end
end
Cucumber is a tool to write human-readable tests that are mapped into code. With it, you can rewrite the above example like this:
Scenario: Signup process
Given a user exists with email "user#example.com" and password "caplin"
When I try to login with "user#example.com" and "caplin"
Then I should be logged in successfully
The almost plain-text interpretation is useful to pass around non-developers but also need some code mapped into it to actually work (the step definitions).
Usually you will use Capybara if you're testing a website and use Cucumber if you need to share those tests with non-developers. These two conditions are independent so you can use one without the other or both or none.
PS: in the code snippet there is some RSpec as well. This is needed because Cucumber or Capybara by themselves cannot test something. They rely on RSpec, Test::Unit or minitest to do the actual "Pass or Fail" work.
cucumber is a BDD tool that expresses testing scenarios in a business-readable, domain-specific language.
capybara is an automated testing tool (often used) for ROR applications.
On the capybara github page, there's an example on using capybara with cucumber.
Cucumber is a general-purpose BDD tool. It knows nothing about web apps. So Cucumber step definitions call Capybara in order to test web apps.
|-------------------------------|-------------------------------|
| Cucumber | Capybara |
|-------------------------------|-------------------------------|
| Test cases are more readable | Test cases are not readable; |
| and written in plain english | Capybara also wraps RSpec and |
| text as a DSL | you follow the same pattern to|
| | write test cases |
|-------------------------------|-------------------------------|
| Easy to iterate data using | Not easy to iterate data |
| tables | |
|-------------------------------|-------------------------------|
| Cucumber has its own runner | Uses RSpec runner to execute |
| | tests |
|-------------------------------|-------------------------------|
| Default HTML reporter | No default HTML reporter |
|-------------------------------|-------------------------------|
| Need to learn cucumber regex | No such concept |
| pattern to write step- | |
| definition which is the middle| |
| man for test case and script. | |
| Btw, the regex pattern is not | |
| essential for all cases. | |
|-------------------------------|-------------------------------|
| You can use the native | (Wrapper)/Built on top of |
| selenium-webdriver methods | selenium-webdriver ruby |
| while using Cucumber; Cucumber| library when used with |
| is just an additional | selenium; it can also be used |
| framework to your generic | with two other drivers. |
| automation framework | |
|-------------------------------|-------------------------------|
| Pure BDD framework (In theory | Traditional functional test |
| BDD sounds great. In practice,| model for end-to-end testing |
| product owners and developers | |
| rarely continue to use BDD) | |
|-------------------------------|-------------------------------|
I'm trying to use Cucumber and Factory Girl. The following lines:
Given I am not logged in
And the following user exists:
| login | email | password | confirmation |
| user50 | user50#mydomain.com | secret50 | secret 50 |
....
raises the following error:
Undefined step: "the following user exists:" (Cucumber::Undefined exception)
/home/user/RubymineProjects/project/features/sign_in.feature:9:in `And the following user exists:
You can implement step definitions for undefined steps with these snippets:
And /^the following user exists:$/ do |table|
# table is a Cucumber::Ast::Table
pending # express the regexp above with the code you wish you had
end
'
I've installed factory_girl_rails (even RubyMine's code completion feature works with Factory Girl step ... )
#Gemfile
group :test do
gem "cucumber-rails", ">= 0.3.2"
gem "factory_girl_rails"
end
#features/support/env.rb
require 'factory_girl'
require 'factory_girl/step_definitions'
Any ideas? Thanks
Update: Thanks to #sj26 and #twmills I realized that I forgot to create a :user factory with Factory Girl. Once I created it, everything worked well.
For those people, who trying to use FactoryGirl helpers now:
From FactoryGirl 3.5.0 these step helpers are deprecated and removed in 4.0.0: http://robots.thoughtbot.com/post/25650434584/writing-better-cucumber-scenarios-or-why-were
As of FactoryGirl 3.5.0, using any of FactoryGirl’s generated step
definitions will print out a deprecation warning. We’ll be removing
the step definitions completely in the 4.0.0 release of FactoryGirl in
accordance with SemVer. I imagine the existing code will be extracted
to a gem similar to Cucumber Rails’ training wheels with a nice
warning urging developers not to use the the steps.
So if you want to use FactoryGirl in Cucumber you should use it in your own step definitions.
You need to include your factories first. factory_girl/step_definitions will iterate over your defined factories to define a step for each.
I use this in features/support/factory_girl.rb:
# Require factories...
require 'spec/factories'
# Then define steps based on factories.
require 'factory_girl/step_definitions'
Try this in features/step_definitions/user_steps.rb
Given /^the following user exists:$/ do |users|
users.hashes.each do |user|
Factory(:user,user)
end
end
Although you may want this instead:
Given /^the following users:$/ do |users|
etc..
Ok, I get that ThoughtBot wants us to write better code, but as an upgrade crutch, we can just put this old file in features/step_definitions:
https://raw.github.com/thoughtbot/factory_girl/3.6.x/lib/factory_girl/step_definitions.rb
For the XMPP interface for the Stack Overflow chat I am parsing the JSON feed from chat and generating Ruby objects for every chat events, such as messages sent, edits sent, users logging in or out, etc. I also generate events for "slash-commands" sent to the XMPP server, like "/help" or "/auth" in order to allow the XMPP user to authenticate with their Stack Overflow chat account.
I have set up these classes in a hierarchy I feel makes good logical sense:
class SOChatEvent # base class
|
|--- class SOXMPPEvent # base for all events that are initiated via XMPP
| |
| |--- class SOXMPPMessage # messages sent to the XMPP bridge via XMPP
| | |
| | |--- class SOXMPPMessageToRoom # messages sent from an XMPP user to an XMPP MUC
| | |
| | |--- class SOXMPPUserCommand # class for "slash commands", that is, messages starting
| | | | # with /, used for sending commands to the bridge
| | | |
| | | |--- class SOXMPPUserHelpCommand
| | | |--- class SOXMPPUserLoginCommand
| | | |--- class SOXMPPUserBroadcastCommand
|
|--- class SOChatRoomEvent # base class for all events that originate from an SO chat room
| |
| |--- class SOChatMessage # messages sent to an SO chat room via the SO chat system
| | |
| | |--- class SOChatMessageEdit # edits made to a prior SOChatMessage
| |
| |--- class SOChatUserEvent # events related to SO chat users
| | |
| | |--- class SOChatUserJoinRoom #Event for when a So user joins a room
| | |--- class SOChatUserLeaveRoom #Event for when a So user leaves a room
(etc)
You can see the full hierarchy and source in Trac or via SVN.
My question is twofold: First, what is the best way to instantiate these events? What I'm currently doing is parsing the JSON events using a giant switch statement --well, it's ruby so it's a case statement -- and, it's not giant yet, but it will be if I continue this way:
rooms.each do |room|
rid = "r"+"#{room.room_id}"
if !data[rid].nil?
#last_update = data[rid]['t'] if data[rid]['t']
if data[rid]["e"]
data[rid]["e"].each do |e|
puts "DEBUG: found an event: #{e.inspect}"
case e["event_type"]
when 1
event = SOChatMessage.new(room,e['user_name'])
event.encoded_body = e['content']
event.server = #server
events.push event
when 2
event = SOChatMessageEdit.new(room,e['user_name'])
event.encoded_body = e['content']
event.server = #server
events.push event
when 3
user = SOChatUser.new(e['user_id'], e['user_name'])
event = SOChatUserJoinRoom.new(room,user)
event.server = #server
events.push event
when 4
user = SOChatUser.new(e['user_id'], e['user_name'])
event = SOChatUserLeaveRoom.new(room,user)
event.server = #server
events.push event
end
end
end
end
end
But I imagine there has to be a better way to handle that! Something like SOChatEvent.createFromJSON( json_data )... But, what's the best way to structure my code so that objects of the proper subclass are created in response to a given event_type?
Second, I'm not actually using ant subclasses of SOXMPPUserCommand yet. Right now all commands are just instances of SOXMPPUserCommand itself, and that class has a single execute method which switches based upon regex of the command. Much the same problem -- I know there's a better way, I just am not sure what the best way is:
def handle_message(msg)
puts "Room \"#{#name}\" handling message: #{msg}"
puts "message: from #{msg.from} type #{msg.type} to #{msg.to}: #{msg.body.inspect}"
event = nil
if msg.body =~ /\/.*/
#puts "DEBUG: Creating a new SOXMPPUserCommand"
event = SOXMPPUserCommand.new(msg)
else
#puts "DEBUG: Creating a new SOXMPPMessageToRoom"
event = SOXMPPMessageToRoom.new(msg)
end
if !event.nil?
event.user = get_soxmpp_user_by_jid event.from
handle_event event
end
end
and:
class SOXMPPUserCommand < SOXMPPMessage
def execute
case #body
when "/help"
"Available topics are: help auth /fkey /cookie\n\nFor information on a topic, send: /help <topic>"
when "/help auth"
"To use this system, you must send your StackOverflow chat cookie and fkey to the system. To do this, use the /fkey and /cookie commands"
when "/help /fkey"
"Usage: /fkey <fkey>. Displays or sets your fkey, used for authentication. Send '/fkey' alone to display your current fkey, send '/fkey <something>' to set your fkey to <something>. You can obtain your fkey via the URL: javascript:alert(fkey().fkey)"
when "/help /cookie"
"Usage: /cookie <cookie>. Displays or sets your cookie, used for authentication. Send '/cookie' alone to display your current fkey, send '/cookie <something>' to set your cookie to <something>"
when /\/fkey( .*)?/
if $1.nil?
"Your fkey is \"#{#user.fkey}\""
else
#user.fkey = $1.strip
if #user.authenticated?
"fkey set to \"#{#user.fkey}\". You are now logged in and can send messages to the chat"
else
"fkey set to \"#{#user.fkey}\". You must also send your cookie with /cookie before you can chat"
end
end
when /\/cookie( .*)?/
if $1.nil?
"Your cookie is: \"#{#user.cookie}\""
else
if $1 == " chocolate chip"
"You get a chocolate chip cookie!"
else
#user.cookie = $1.strip
if #user.authenticated?
"cookie set to \"#{#user.cookie}\". You are now logged in and can send messages to the chat"
else
"cookie set to \"#{#user.cookie}\". You must also send your fkey with /fkey before you can chat"
end
end
end
else
"Unknown Command \"#{#body}\""
end
end
end
I know there's a better way to do this, just not sure what specifically it is. Should the responsibility of creating subclasses of SOXMPPUserCommand fall on SOXMPPUserCommand itself? Should all subclasses register with the parent? Do I need a new class?
What's the best way to instantiate objects of subclasses in such a hierarchal structure?
Addressing your first question. Here's some ideas you might like to consider
First, structure you sub-classes so they all use the same initiation parameters. Also, you could put some of the other initiating code there as well (such as your encoded_body and server accessors. Here's a skeleton of what I mean:
# SOChat Class skeleton structure
class SOChatSubClass #< inherit from whatever parent class is appropriate
attr_accessor :encoded_body, :server, :from, :to, :body
def initialize(event, room, server)
#encoded_body = event['content']
#server = server
SOChatEvent.events.push event
#class specific code
xmpp_message = event['message']
#from = xmpp_message.from
#to = xmpp_message.to
#body = xmpp_message.body
#use super to call parent class initialization methods and to DRY up your code
end
end
Note that in my example you'll still have duplicated code in the sub-classes. Ideally you'd pull out the duplication by putting it in the appropriate parent class.
If you have problems creating a common list of initiation parameters, then rather than pass in a list of arguments (event, room, server), change the classes to accept an argument list as a hash {:event => event, :room => room, :server => server, etc}.
Regardless, once you have a common parameter structure for initializing the classes, you can initialize them a bit more dynamically, eliminating the need for the case statement.
class SOChatEvent
class << self; attr_accessor :events; end
#events = []
##event_parser = {
0 => SOChatSubClass, #hypothetical example for testing
1 => SOChatMessage,
2 => SOChatMessageEdit,
#etc
}
def self.create_from_evt( json_event_data, room=nil, server=nil)
event_type = json_event_data["event_type"]
event_class = ##event_parser[event_type]
#this creates the class defined by class returned in the ##event_parser hash
event_obj = event_class.new(json_event_data, room, server)
end
#rest of class
end
##event_parser contains the mapping between event type and the class to implement that event type. You just assign the appropriate class to a variable and treat it just like the actual class.
Code like the following would create an object of the appropriate class:
event_obj = SOChatEvent.create_from_evt( json_event_data,
"some room",
"some server")
Note: There are further optimizations that could be done to what I provided to be even cleaner and more concise, but hopefully this helps you get over the hump of the case statement.
Edit: I forgot to mention the Class instance variable SOChatEvent.events created with this:
class << self; attr_accessor :events; end
#events = []
You were pushing events to an event stack, but I wasn't clear where you wanted that stack to exist and whether it was a global events list, or specific to a particular class. The one I did is global, so feel free to change it if you wanted the event stack constrained to certain classes or instances.