You are currently browsing the tag archive for the 'RSpec' tag.
On my new project we had the problem that some specs failed when ran on their own, and some specs produces strange output (like “use object_id”), so I build a helper that runs each test on its own and could pinpoint the problem.
rake spec:one_by_one
it is now included in the single test rails plugin
What good is a dual-core when you do not use it !?
rake spec:parallel[1] –> 86 seconds
rake spec:parallel[2] –> 47 seconds
rake spec:parallel[4] –> 26 seconds
grab the parallel specs rails plugin here!
It requires a bit of setup, but hey: Can you spare 5 minutes now to save 1 minute 100 times a day ?
You just have to love this “syntax” ![]()
Story
#features/discussion.feature
Scenario: I add to an discussion
Given I am logged in
And a "Discussion" exists for "Festival" "1"
And I am on "Festival" "1"
When I fill in "Text" with "Halloo"
And I press "Send"
Then I should be on "Festival" "1"
And I should see "Halloo"
Steps
#features/step_definitions/common_steps.rb # On page/record Given /^I am on "([^"]*)"$/ do |path| visit path end Then /^I should be on "([^"]*)"$/ do |path| current_path.should == path end Given /^I am on "([^"]*)" "([^"]*)"$/ do |model,number| visit polymorphic_path(record_from_strings(model,number)) end Then /^I should be on "([^"]*)" "([^"]*)"$/ do |model,number| current_path.should == polymorphic_path(record_from_strings(model,number)) end # Existing Given /^a "([^"]*)" exists for "([^"]*)" "([^"]*)"$/ do |associated,model,number| record = record_from_strings(model,number) record.send(associated.underscore+'=',valid(associated)) record.save! end # Login Then /^I should be logged in$/ do should be_logged_in end Given /^I am logged in$/ do visit 'login' fill_in 'email', :with=>'quentin@example.com' fill_in 'password', :with=>'test' click_button 'Login' end # Support def current_path response.request.request_uri end def record_from_strings(model,number) model.constantize.find(:first,:offset=>number.to_i-1) end
env.rb
#features/support/env.rb #load all fixtures include AuthenticatedTestHelper #restful_authentification include ValidAttributes #http://github.com/grosser/valid_attributes
I finally found some time to mess with cucumber, its pretty nice but has some edges and quircks… but for now i like it
Install
This was rather hard… (these libraries and frex should not be necessary for mac)
sudo apt-get install libxslt1-dev libxml2-dev racc sudo gem install aaronp-frex brynary-webrat sudo gem install cucumber ./script/generate cucumber rake features
First story
#features/signup.feature
Feature: Signup
Scenario: A new user comes to the page and wants to register.
Given I am on "/"
When I click "register"
And I fill in "user[name]" with "Michael G"
And I fill in "Email" with "test@test.de"
And I fill in "Password" with "test"
And I fill in "Password confirmation" with "test"
And I press "Register for the free basic account"
Then I should be on "/"
And I should be logged in
And I should see a flash about "activation"
Environment setup
#append to features/support/env.rb #load all fixtures -- http://pragmatig.wordpress.com/2008/12/25/load-all-fixtures-when-not-in-test/ include AuthenticatedTestHelper # restful authentification include RspecResponseEnhancer # http://pragmatig.wordpress.com/2008/04/20/rspec-responseshould-information-enhancers/
Common steps
There is a nice collection of steps already available in steps/webrat_steps, but some basics where missing….
#features/step_definitions/common_steps.rb
When /^I click "(.*)"$/ do |link|
click_link(link)
end
When /^I am on "(.*)"$/ do |path|
header('Accept-Language','EN-en')
visit path
end
Then /^I should be on "(.*)"$/ do |path|
response.request.request_uri.should == path
end
Then /^I should see a flash about "(.*)"/ do |message|
doc.search('div.flash_notice').inner_html.include?(message).should be_true
end
Then /^I should be logged in$/ do
should be_logged_in
end
def doc
Hpricot(response.body)
end
Output
rake features
Feature: Signup # features/signup.feature
Scenario: A new user comes to the page and wants to register. # features/signup.feature:2
Given I am on "/" # features/step_definitions/common_steps.rb:6
When I click register # features/step_definitions/common_steps.rb:1
And I fill in "user[name]" with "Michael G" # features/step_definitions/webrat_steps.rb:12
And I fill in "Email" with "test@test.de" # features/step_definitions/webrat_steps.rb:12
And I fill in "Password" with "test" # features/step_definitions/webrat_steps.rb:12
And I fill in "Password confirmation" with "test" # features/step_definitions/webrat_steps.rb:12
And I press "Register for the free basic account" # features/step_definitions/webrat_steps.rb:4
Then I should be on "/" # features/step_definitions/common_steps.rb:11
And I should be logged in # features/step_definitions/common_steps.rb:19
And I should see a flash about "activation" # features/step_definitions/common_steps.rb:15
10 steps passed
Feels great to write stories again, sadly takes more time then unit tests, but the readability is superb! IMO a very nice way of doing integration tests…
TDD often is well understood, but seldom put to good use. Spikes grow larger, hard to test aspects are skipped and sooner or later your test coverage looks like this.
.
Therefore i want to show you the Black-White-Tree testing method, which is easy to adopt and results in full C1(path) coverage with easy to maintain, independent tests.
.
.
The principle is simple:
When designing a new method build Black-Box tests for it, often 2-3 are sufficient if they exersice all paths within this method(not necessarily its sub-methods), represented by the trunk and the black branches.
describe :price do
it "sums prices and applies discounts" do
Order.new(:items=>items,:discount=>20).price.should == 22.5
end
it "costs nothing if it is free" do
Order.new(:items=>items,:free=>true,:discount=>10).price.should == 0
end
end
Then write White Box tests, for the public method, mocking everything out with forged return values to verify that every method is called and the call-results are used logically.
describe :price do
...
it "uses sum_price and apply_discount" do
order = Order.new(:items=>items,:discount=>10)
order.expects(:sum_prices).returns 100
order.expects(:apply_discount).with(10,100).returns 20
order.price.should == 20
end
end
Then build the method, making all White Box and some of the Black Box tests pass.
Repeat for every sub-method.


