By Sampat Badhe
RSpec is a Behaviour-Driven Development tool for Ruby programmers. BDD is an approach
to software development that combines Test-Driven Development, Domain Driven Design,
and Acceptance Test-Driven Planning. RSpec helps you do the TDD part of that equation,
focusing on the documentation and design aspects of TDD.
2. describe FindReaction do
#Spec 1
it "should return no reaction template when there are no reaction templates" do
post = create :post, locale: "en", type: "basic"
reaction = FindReaction.for(post).reaction
expect(reaction.blank?).to be_true
end
#Spec 2
it "should return no reaction template if reaction templates exist, but non fitting" do
post = create :post, locale: "en", type: "basic"
reaction1 = ReactionTemplate.create locale: "de", subtypes: ["basic", "top_x"]
reaction2 = ReactionTemplate.create locale: "en", subtypes: ["slideshow", "top_x"]
reaction = FindReaction.for(post).reaction
expect(reaction.blank?).to be_true
end
3. #Spec 3
it "should return the right reaction if it exists" do
post = create :post, locale: "en", type: "basic"
reaction1 = ReactionTemplate.create locale: "en", subtypes: ["basic", "top_x"]
reaction2 = ReactionTemplate.create locale: "en", subtypes: ["basic", "top_x"]
reaction3 = ReactionTemplate.create locale: "en" , subtypes: ["slideshow",
"top_x"]
reaction = FindReaction.for(post).reaction
expect(reaction.blank?).to be_true
expect(reaction).to eq reaction2
end
#Spec 4
it "should change posts reaction_template when attaching it" do
post = create :post, locale: "en", type: "basic"
expect(post.reaction_template.nil?).to be_true
reaction = ReactionTemplate.create locale: "en", subtypes: ["basic", "top_x"]
FindReaction.for(post).attach
expect(post.reaction_template.nil?).to be_false
expect(post.reaction_template).to eq reaction
end
end
5. Use before :all instead of before
:each when possible
6. Use conditional hooks
• Sometimes if you want to execute some piece of code only
for one example but not for all examples in a context then
you can use conditional hooks.
context "#update" do
before(:each, run: true) do
# do something
end
it "example1", run: :true
it "example2"
end
• Now before(:each) will run only for first example but not
for second example.
8. Use describe to create nested
specs groups. describe should
relate to an operation or an object
9. Use variables instead of constants
to keep your specs from becoming
too fragile.
10. Use RSpec’s magnificent be_
syntactic sugar
RSpec has many syntactic sugars that makes your specs more readable.
for example:
expect(reaction.blank?).to be_true
When an object reacts to some_method_name? RSpec allows you to write
the test in the following way:
object.should be_some_method_name
Or in our case:
expect(reaction).to be_blank
13. Use subject/it clauses to keep your
specs DRY’er and cleaner
result: FindReaction.for(@post).reaction
This can be easily extracted into
subject {FindReaction.for(@post).reaction}
14. One assertion per test case
• This way if the spec fails, you immediately
know what went wrong and don’t even have
to look at the detailed output of the failure. It
also keeps your specs clean and focused on
what they’re supposed to test
15. Use RSpec’s expect {} block to
describe a change in the state of an
object
RSpec has a nice and clean way to describe these
kind of state changes:
expect { some_operation }.to
change{something}.from(initial_value).to(final_value
)
It is much cleaner and more readable this way.
16. Use shared examples.
• When you want to test the same functionality across different subjects, for example different kinds
of users, use shared examples.
context "#edit" do
it "admin should be able to edit his profile"
it "distributor should be able to edit his profile"
End
You can write as
context "#edit" do
shared_examples "profile_editing" do
it "user should be able to edit his profile"
end
context "admin" do
include_examples "profile_editing"
it "should be able see to list of distributors"
end
context "distributor" do
include_examples "profile_editing"
it "should not able to see list of distributors"
end
End
Note - A word of caution – you may lost readability if you use too many shared examples in single file
18. Use the new syntax for object
creation
• Use the new FactoryGirl syntax that is
supported in factory_girl4. This helps the code
be clean
create(:user)
instead of
FactoryGirl.create(:user)
19. Use expect and not should syntax
• It’s just nice and clean!
expect(User.all.count).to eq(1)
instead of
User.all.count.should == 1
Note :- Use the Transpec gem helps you to convert
from should syntax to expect syntax
21. describe FindReaction do
before :all do
@post = build :post, locale: "en", type: "basic"
end
before :each do
@post.reaction = nil
end
describe :reaction do
subject { FindReaction.for(@post).reaction }
#Spec 1
context "there are no reaction templates" do
it {expect(subject).to be_blank }
end
#Spec 2
context "reaction templates exist, but non fitting" do
before :each do
reaction1 = ReactionTemplate.create! locale: "de", subtypes: ["basic", "top_x"]
reaction2 = ReactionTemplate.create! locale: "en", subtypes: ["slideshow", "top_x"]
end
it {expect(subject).to be_blank }
end
22. #Spec 3
context "fitting reaction templates exist" do
before :each do
@reaction1 = ReactionTemplate.create! locale: @post.locale, subtypes: [@post.type, "top_x"]
@reaction2 = ReactionTemplate.create! locale: @post.locale, subtypes: [@post.type, "top_x"]
@reaction3 = ReactionTemplate.create! locale: @post.locale, subtypes: ["slideshow", "top_x"]
end
it {expect(subject).not_to be_blank}
it {expect(subject).to eq @reaction2}
end
end
describe :attach do
#Spec 4
context "attaching a reaction to post" do
before :each do
@reaction = ReactionTemplate.create! locale: @post.locale, subtypes: [@post.type, "top_x"]
end
it "should change posts reaction template" do
expect {
FindReaction.for(@post).attach
}.to change{@post.reaction_template}.from(nil).to(@reaction)
end
end
end
end
23. CONCLUSION
• Our test-suite runs faster
• Our test file is more readable
• The failure output provided by RSpec is better
• We’re not repeating ourselves between specs
• It is extremely easy to extend the specs to
describe new features