You are currently browsing the tag archive for the ‘RSpec’ tag.
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.
Small option, but took me 2 hours to find :/
This will automatically generate reports for your test-runs.
It only shows single examples, which is sad since i would also want to know which controller_specs take the longest…
Output:
Top 10 slowest examples: 0.5215740 User downgrades to a person 0.4326950 User finds invalid 0.1914630 User remembering unsets remember token 0.1218360 User is valid 0.0903790 Festival is valid
Install:
#spec/spec.opts --format profile:spec/profile.txt
Since no one wants to write the documentation, the simplest solution would be to let everyone write documentation, without noticing…
Normal documentation:
An Organisation is a firm or school that has an address(required) and can have users as members.
Pragmatig documentation with examples:
Organisation: - requires an address organisation.address - can have users as members organisation.members << User
Test:
describe Organisation do
it "requires an address" do
@organisation.should_not be_valid?
@organisation.address = Address.new
@organisation.should be_valid
end
it "can have users as members" do
@organisation.should be_valid
@organisation.members << User.new
@organisation.should be_valid
end
end
#before :each omitted
With the help of some spec -f or agiledox magic, we can extract:
An Organisation: - requires an address - can have users as members
looks familliar ?
I prefer this kind of testing, since it does not generate so many 3-liners(2(do/end)+1) nor uses “it should” all the time, which makes it look more documentation-ish.
DISCLAIMER: This way of writing tests is not RSpec-pure in that it does not use ‘it should’ and has more than on assertion (should) per example.


