2. Cover
- What is Rspec?
- RSpec features
- RSpec in action
- Stubs & Mocks
- Stubs & Mocks using RSpec
3. What is RSpec ?
- Testing framework for Ruby on Rails.
- Replacement for RoR built-in testing tool.
4. TestUnit
class Calculator < Test::Unit::TestCase
def test_addition
assert_equal(8, Calculator.new(6, 2).addition)
end
def test_subtraction
assert_same(4, Calculator.new(6, 2).subtraction)
end
end
5. RSpec
desribe Calculator do
let(:calculator) { Calculator.new(6,2) }
it "should return 8 when adding 6 and 2" do
calculator.addition.should eql(8)
end
it "should return 4 when subtracting 2 from 6" do
calculator.subtraction.should eql(4)
end
end
6. RSpec basics
describe MyClass do # creates initial scope
before do
@object = MyClass.new
end
describe "#some_method" do # creates new scope
it "should ..." do
@object.should ...
end
context "when authorized" do # creates new scope
before do
@object.authorized = true
end
7. RSpec basics (Con.)
it "should ..." do
@object.should ...
end
end
context "when not authorized" do # creates new scope
it "should ..." do
@object.should ...
end
end
end
it "should ..." do
pending "Fix some model first" # creates pending test
end
end
9. Readability
describe Campaign do
it "should be visible by default" do
campaign.should be_visible
end
it "should have performances visible by default" do
campaign.performances_visible.should be_true
end
it "should not be published at start" do
campaign.should_not be_published
end
10. Readability (Con.)
it "should not be ready to publish at start - without performances, etc" do
campaign.should_not be_ready_to_publish
end
describe "#allowed_performance_kinds" do
it "should allow all by default" do
campaign.allowed_performance_kinds.should == Performance.kinds
end
end
end
14. Test run filters
def old_ruby
RUBY_VERSION != "1.9.2"
end
describe TrueClass do
it "should be true for true", :if => old_ruby do
true.should be_true
end
it "should be true for String", :current => true do
"".should be_true
end
15. Test run filters (Cons.)
it "should be true for Fixnum" do
0.should be_true
end
end
20. Problems ?
- Hard to learn at the beginning
- Routing tests could have more detailed failure messages
- Rails upgrade can break tests compatibility
21. RSpec in action
- Model specs (placed under spec/models director)
- Controller specs (placed under spec/controllers directory)
- Helper specs (placed under spec/helpers directory)
- View specs (placed under spec/views directory)
- Routing specs (placed under spec/routing directory)
22. Model specs
describe Campaign do
it "should be visible by default" do
campaign.should be_visible
end
it "should have performances visible by default" do
campaign.performances_visible.should be_true
end
it "should not be published at start" do
campaign.should_not be_published
end
23. Model specs (Cons.)
it "should not be ready to publish at start - without performances, etc" do
campaign.should_not be_ready_to_publish
end
describe "#allowed_performance_kinds" do
it "should allow all by default" do
campaign.allowed_performance_kinds.should == Performance.kinds
end
end
end
24. Controller specs
describe SessionsController do
render_views
describe "CREATE" do
context "for virtual user" do
before do
stub_find_user(virtual_user)
end
it "should not log into peoplejar" do
post :create, :user => {:email => virtual_user.email,
:password => virtual_user.password }
response.should_not redirect_to(myjar_dashboard_path)
end
end
25. Controller specs (Cons.)
context "for regular user" do
before do
stub_find_user(active_user)
end
it "should redirect to myjar when login data is correct" do
post :create, :user => {:email => active_user.email,
:password => active_user.password }
response.should redirect_to(myjar_dashboard_path)
end
end
end
end
26. Helper specs
describe CampaignsHelper do
let(:campaign) { Factory.stub(:campaign) }
let(:file_name) { "meldung.jpg" }
it "should return the same attachment URL as paperclip
if there is no attachment" do
campaign.stub(:featured_image_file_name).and_return(nil)
helper.campaign_attachment_url(campaign, :featured_image).
should eql(campaign.featured_image.url)
end
it "should return the same attachment URL as paperclip if there
is attachment" do
campaign.stub(:featured_image_file_name).and_return(file_name)
29. View specs (Cons.)
# spec at spec/views/campaigns/index.html.erb_spec.rb
describe "campaigns/index.html.erb" do
let(:campaign) { Factory.stub(:campaign) }
it "displays pagination when there are more than 20 published
campaigns" do
assign(:campaigns, (1..21).map { campaign }.
paginate(:per_page => 2) )
render
rendered.should include("Prev")
rendered.should include("Next")
end
end
30. Routing specs
describe "home routing", :type => :controller do
it "should route / to Home#index" do
{ :get => "/" }.should route_to(:controller => "home", :action => "index",
:subdomain => false)
end
it "should route / with subdomain to Performances::Performances#index
do
{ :get => "http://kzkgop.test.peoplejar.net" }.
should route_to(:namespace => nil, :controller =>
"performances/performances", :action => "index")
end
end
31. Routing specs (Cons.)
describe "error routing", :type => :controller do
it "should route not existing route Errors#new" do
{ :get => "/not_existing_route" }.should route_to(:controller => "errors",
:action => "new", :path => "not_existing_route")
end
End
describe "icebreaks routing" do
it "should route /myjar/icebreaks/initiated to
Icebreaks::InitiatedIcebreaks#index" do
{ :get => "/myjar/icebreaks/initiated" }.should
route_to(:controller => "icebreaks/initiated_icebreaks",
:action => "index")
end
end
32. Routing specs (Cons.)
describe "admin routing" do
it "should route /admin to Admin::Base#index" do
{ :get => "/admin" }.should route_to(:controller => "admin/welcome",
:action => "index")
end
end
34. Back to unit test assumptions
- A unit is the smallest testable part of an application
- The goal of unit testing is to isolate each part of the program and show
that the individual parts are correct
- Ideally, each test case is independent from the others
35. you.should use_stubs!
- Isolate your unit tests from external libraries and dependencies
- Propagate skinny methods which has low responsibility
- Single bug should make only related tests fail
- Speed up tests
37. Are there any problems ?
- Writing test is more time consuming
- Need to know stubbed library internal implementations
- Need to write an integration test first
43. What's the difference between
Stubs and Mocks
- Mocks are used to define expectations and verify them
- Stubs allows for defining eligible behavior
- Stubs will not cause a test to fail due to unfulfilled expectation
44. In practice - Stub failure
describe ".to_csv_file" do
it "should generate CSV output" do
User.stub(:active).and_return([user])
User.to_csv_file.should == "#{user.display_name},#{user.email}n"
end
end
45. In practice - Mock failure
describe "#facebook_uid=" do
it "should build facebook setting instance if not exists when setting uid"
do
user.should_receive(:build_facebook_setting).with(:uid => "123")
user.facebook_uid = "123"
end
end