Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
SlideShare a Scribd company logo
Rspec Best Practices
      Ruby Social Club Milano
           24 February 2011




                   Andrea Reginato
             twitter/andreareginato
I'll not teach RSpec
You have good books and web sites
                  The RSpec Book
            Rails Test Prescriptions




                   twitter/andreareginato
I'll tell you how I use RSpec
      What I've learned reading books
             some articles on the web
              but most important from
         my everyday job experience




                      twitter/andreareginato
Just a little introduction
 RSpec is a library that focus on
    testing the behavior of your
                everyday project




                  twitter/andreareginato
Why people do not use it
 Probably the testing practice is the
      most diffcult forma mentis a
            developer have to learn




                     twitter/andreareginato
It will save our life, maybe
  In the long term, you will not check
        your web page everytime you
     make a new feature, but you will
            check if your test passed




                      twitter/andreareginato
Short descriptions
# wrong
it "should have 422 status code if an
    unexpected params will be added" do
  response.should respond_with 422
end

# correct
context "when not valid"
  it { should respond_with 422 }
(over)use contexts
                          and use with/when as keys

# wrong
it "should have 200 status code if
    logged in" do
  response.should respond_with 200
end

# correct
context "when logged in" do
  it { should respond_with 200 }
end
Describe methods
# wrong
describe "the authenticate method for
           User logged in" ...
describe "if the user is an admin" do


# correct
describe ".authenticate" do
describe "#admin?"
Single expectation test
# wrong
it "should create a resource" do
  response.should respond_with_content_type(:json)
  response.should assign_to(:resource)
end


# correct
it { should respond_with_content_type(:json) }
it { should assign_to(:resource) }
Test the edge cases
# sample action
def destroy
  @resource = Resource.where(:id => params[:id])
  if @resource
    @resource.destroy
    head 204
  else
    render :template => "shared/404", :status => 404,
  end
end



What would you test ?
Test the edge case
# correct
describe "#destroy" do
  context "when resource is found" do
    it "should render_with 204"
    it "should assign @resource"
  context "when resource is not found" do
    it "should render with 404"
    it "should not assign @resource"
  end
end


Is this enough ?
Use the subject
# wrong
it { assigns("message").should match
     /The resource name is Genoveffa/ }
it { assigns("message").should match
     /it was born in Billyville/ }
it { assigns("message").creator.should match
     /Claudiano/ }

# correct
subject { assigns("message") }
it { should match /The resource name is Genoveffa/ }
it { should match /it was born in Billyville/ }
its(:creator) { should match /Claudiano/ }
Mock or not to mock
# wrong (a really personal point of view)
1) It's wrong when you never mock and recreate by code
a “medium complex” situation and it's time consuming
2) It's wrong when you mock everything. You have a light
system and the big advantage of independence, but you loose
part of the control on your application.

# correct
# simulate authenticated user
controller.stub!(:authenticate).and_return(true)
# simulate current user
controller.stub(:current_user).and_return(current_user)
# simulate not found record
Resource.stub(:where).with(created_from: id)
                     .and_return(false)
Create data when needed
# wrong
You shouldn't use fixtures
* loose control on our data
* load everything all the time
* difficult to find problems

# correct
describe "User"
  describe ".top" do
    before { 3.times { Factory(:user) } }
    it { User.top(2).should have(2).item }
  end
end
Shared examples to DRY
# wrong
context "when own resources" do
  it "should have it" do
    resource = Factory("user")
    do_get format: json
    assigns(users).should include(resource)
  end
end

context "when does not own resource" do
  it "should not have it" do
    not_owned_resource = Factory("unknown")
    do_get format: json
    assigns(users).should_not include(not_owned_resource)
  end
end
Shared examples to DRY
# correct (but why?)
shared_examples for "a secure resource" do
  context "when own the resource" do
    it "should have it" do
      resource = Factory("user")
      do_get format: json
      assigns(users).should include(resource)
    end
  end
  context "when does not own resource" do
    it "should not have it" do
      not_owned_resource = Factory("unknown")
      do_get format: json
      assigns(users).should_not include(not_owned_resource)
    end
  end
end
Shared examples to DRY
# correct (apply DRY on tests)
describe "#show" do
  it_should_behave_like "a secure resource"
  it_should_behave_like "a findable resource"
  it_should_behave_like "a secure resource"
  context "when not logged in" do
    it_should_handle "a not authenticated request"
  end
end
More?
# wrong
Do not use RSpec

# correct
Start using RSpec 2 into your next project
Thanks
# more info
Click here to fnd a public document with a
summary of all best practices


# contacts
andrea.reginato@gmail.com
twitter/andreareginato

More Related Content

RSpec 2 Best practices

  • 1. Rspec Best Practices Ruby Social Club Milano 24 February 2011 Andrea Reginato twitter/andreareginato
  • 2. I'll not teach RSpec You have good books and web sites The RSpec Book Rails Test Prescriptions twitter/andreareginato
  • 3. I'll tell you how I use RSpec What I've learned reading books some articles on the web but most important from my everyday job experience twitter/andreareginato
  • 4. Just a little introduction RSpec is a library that focus on testing the behavior of your everyday project twitter/andreareginato
  • 5. Why people do not use it Probably the testing practice is the most diffcult forma mentis a developer have to learn twitter/andreareginato
  • 6. It will save our life, maybe In the long term, you will not check your web page everytime you make a new feature, but you will check if your test passed twitter/andreareginato
  • 7. Short descriptions # wrong it "should have 422 status code if an unexpected params will be added" do response.should respond_with 422 end # correct context "when not valid" it { should respond_with 422 }
  • 8. (over)use contexts and use with/when as keys # wrong it "should have 200 status code if logged in" do response.should respond_with 200 end # correct context "when logged in" do it { should respond_with 200 } end
  • 9. Describe methods # wrong describe "the authenticate method for User logged in" ... describe "if the user is an admin" do # correct describe ".authenticate" do describe "#admin?"
  • 10. Single expectation test # wrong it "should create a resource" do response.should respond_with_content_type(:json) response.should assign_to(:resource) end # correct it { should respond_with_content_type(:json) } it { should assign_to(:resource) }
  • 11. Test the edge cases # sample action def destroy @resource = Resource.where(:id => params[:id]) if @resource @resource.destroy head 204 else render :template => "shared/404", :status => 404, end end What would you test ?
  • 12. Test the edge case # correct describe "#destroy" do context "when resource is found" do it "should render_with 204" it "should assign @resource" context "when resource is not found" do it "should render with 404" it "should not assign @resource" end end Is this enough ?
  • 13. Use the subject # wrong it { assigns("message").should match /The resource name is Genoveffa/ } it { assigns("message").should match /it was born in Billyville/ } it { assigns("message").creator.should match /Claudiano/ } # correct subject { assigns("message") } it { should match /The resource name is Genoveffa/ } it { should match /it was born in Billyville/ } its(:creator) { should match /Claudiano/ }
  • 14. Mock or not to mock # wrong (a really personal point of view) 1) It's wrong when you never mock and recreate by code a “medium complex” situation and it's time consuming 2) It's wrong when you mock everything. You have a light system and the big advantage of independence, but you loose part of the control on your application. # correct # simulate authenticated user controller.stub!(:authenticate).and_return(true) # simulate current user controller.stub(:current_user).and_return(current_user) # simulate not found record Resource.stub(:where).with(created_from: id) .and_return(false)
  • 15. Create data when needed # wrong You shouldn't use fixtures * loose control on our data * load everything all the time * difficult to find problems # correct describe "User" describe ".top" do before { 3.times { Factory(:user) } } it { User.top(2).should have(2).item } end end
  • 16. Shared examples to DRY # wrong context "when own resources" do it "should have it" do resource = Factory("user") do_get format: json assigns(users).should include(resource) end end context "when does not own resource" do it "should not have it" do not_owned_resource = Factory("unknown") do_get format: json assigns(users).should_not include(not_owned_resource) end end
  • 17. Shared examples to DRY # correct (but why?) shared_examples for "a secure resource" do context "when own the resource" do it "should have it" do resource = Factory("user") do_get format: json assigns(users).should include(resource) end end context "when does not own resource" do it "should not have it" do not_owned_resource = Factory("unknown") do_get format: json assigns(users).should_not include(not_owned_resource) end end end
  • 18. Shared examples to DRY # correct (apply DRY on tests) describe "#show" do it_should_behave_like "a secure resource" it_should_behave_like "a findable resource" it_should_behave_like "a secure resource" context "when not logged in" do it_should_handle "a not authenticated request" end end
  • 19. More? # wrong Do not use RSpec # correct Start using RSpec 2 into your next project
  • 20. Thanks # more info Click here to fnd a public document with a summary of all best practices # contacts andrea.reginato@gmail.com twitter/andreareginato