20
Rspec Best Practices Ruby Social Club Milano Andrea Reginato twitter/andreareginato 24 February 2011

RSpec 2 Best practices

Embed Size (px)

DESCRIPTION

A list of some best practices I've been learning during my daily job.

Citation preview

Page 1: RSpec 2 Best practices

Rspec Best Practices

Ruby Social Club Milano

Andrea Reginatotwitter/andreareginato

24 February 2011

Page 2: RSpec 2 Best practices

I'll not teach RSpec

twitter/andreareginato

The RSpec Book

You have good books and web sites

Rails Test Prescriptions

Page 3: RSpec 2 Best practices

I'll tell you how I use RSpec

twitter/andreareginato

What I've learned reading bookssome articles on the webbut most important from

my everyday job experience

Page 4: RSpec 2 Best practices

Just a little introduction

twitter/andreareginato

RSpec is a library that focus on testing the behavior of your

everyday project

Page 5: RSpec 2 Best practices

Why people do not use it

twitter/andreareginato

Probably the testing practice is the most diffcult forma mentis a

developer have to learn

Page 6: RSpec 2 Best practices

It will save our life, maybe

twitter/andreareginato

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

Page 7: RSpec 2 Best practices

Short descriptions# wrong

# correct

it "should have 422 status code if an unexpected params will be added" do

response.should respond_with 422end

context "when not valid" it { should respond_with 422 }

Page 8: RSpec 2 Best practices

(over)use contexts # wrong

# correct

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

context "when logged in" do it { should respond_with 200 }end

and use with/when as keys

Page 9: RSpec 2 Best practices

Describe methods# wrong

# correct

describe "the authenticate method for User logged in" ...

describe "if the user is an admin" do

describe ".authenticate" dodescribe "#admin?"

Page 10: RSpec 2 Best practices

Single expectation test# wrong

# correct

it "should create a resource" do response.should respond_with_content_type(:json) response.should assign_to(:resource)end

it { should respond_with_content_type(:json) } it { should assign_to(:resource) }

Page 11: RSpec 2 Best practices

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 ?

Page 12: RSpec 2 Best practices

Test the edge case# correctdescribe "#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" endend

Is this enough ?

Page 13: RSpec 2 Best practices

Use the subject# wrong

# correct

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/ }

subject { assigns("message") }it { should match /The resource name is Genoveffa/ }it { should match /it was born in Billyville/ }its(:creator) { should match /Claudiano/ }

Page 14: RSpec 2 Best practices

Mock or not to mock# wrong (a really personal point of view)

# correct

1) It's wrong when you never mock and recreate by code a “medium complex” situation and it's time consuming

# simulate authenticated usercontroller.stub!(:authenticate).and_return(true)# simulate current usercontroller.stub(:current_user).and_return(current_user)# simulate not found recordResource.stub(:where).with(created_from: id)

.and_return(false)

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.

Page 15: RSpec 2 Best practices

Create data when needed# wrong

# correct

You shouldn't use fixtures* loose control on our data* load everything all the time* difficult to find problems

describe "User" describe ".top" do before { 3.times { Factory(:user) } } it { User.top(2).should have(2).item } endend

describe "User" describe ".top" do before { 3.times { Factory(:user) } } it { User.top(2).should have(2).item } endend

Page 16: RSpec 2 Best practices

Shared examples to DRY# wrongcontext "when own resources" do it "should have it" do resource = Factory("user") do_get format: json assigns(users).should include(resource) endend

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) endend

Page 17: RSpec 2 Best practices

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 endend

Page 18: RSpec 2 Best practices

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" endend

Page 19: RSpec 2 Best practices

More?

# correct Start using RSpec 2 into your next project

# wrongDo not use RSpec

Page 20: RSpec 2 Best practices

Thanks

# more info Click here to fnd a public document with a summary of all best practices

[email protected]# contacts

twitter/andreareginato