The document discusses best practices for using RSpec, a testing library for Ruby projects. It provides examples of good and bad ways to write RSpec tests and describes techniques like using contexts and shared examples to organize tests and DRY up code. The document emphasizes testing edge cases, mocking only when needed, creating data dynamically in tests rather than using fixtures, and following practices like describing methods under test and having single-expectation tests. It encourages starting to use RSpec and provides contact information for the author to learn more.
1 of 20
Downloaded 358 times
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