RSpec: What, How and Why


Published on

BDD with RSpec.

Published in: Technology, Education
  • Be the first to comment

No Downloads
Total views
On SlideShare
From Embeds
Number of Embeds
Embeds 0
No embeds

No notes for slide
  • Introduced by Dan North in 2006Found that training people in TDD was hard since the process lacked direction.Mixed DDD(Domain Driven Design) + TDDStart with the requirements. Work inwards.The Tools:A change in language (tests -> specs)Interaction-Based TestingDescriptive Tests
  • The ProcessAs opposed to state-based testing(Test::Unit)Mock all immediate neighbors of a unit.Define Expectations of the mock objectsRun the unit & Check if expectations are metObservationsTests get too intimate with implementationGood/Bad thing?Test behavior not state.Faster if done_right?A true Unit Test – Complete isolation of the unitAssumes that the interface is constant and the state is mutable.
  • 1246 context "when not available in cache" do 1247 before do 1248 @slideshow= Factory(:slideshow, :user_id => 1249 @tag_det= Factory(:tag_det, :slideshow => @slideshow) 1250 end 1251 it "should return it from db" do 1252 @user.tags.should ==[@tag_det] 1253 end 1254 1255 it "should add the data to cache" do 1256 Cache.should_receive(:put).with("TagDet:#{}", [@tag_det], anything) 1257 @user.tags1258 end 1259 end 1260 end
  • RSpec: What, How and Why

    1. 1. RSpec<br />The What, How and Why?<br />
    2. 2. What?<br />
    3. 3. What is Rspec?<br />A BDD Framework for Ruby<br />
    4. 4. What is Rspec?<br />A BDD Framework for Ruby<br />A testing framework that supports BDD<br />
    5. 5. What is BDD<br />/[T|B]DD/: Just Tests ... Right?<br />
    6. 6. /[T|B]DD/: Just Tests ... Right?<br />
    7. 7. 100% Code Coverage is Good.Good Code + 100% Coverage is Better.<br />Feel Free make whatever you want out of the above picture<br />
    8. 8. Enter BDD<br />Dan North(ThoughtWorks)<br />Teaching TDD was hard<br />TDD needed Direction<br />
    9. 9. The Tools of BDD<br />Change Of Focus<br />Interaction-Based Testing<br />A Ubiquitous Language<br />
    10. 10. Change of Focus<br /> Tests have a tendency of loosing focus of what we’re meant to be building. Too low level.<br />test_cases.each {|case| case.shouldadd_business_value}<br />tests which describe domain specific functions => specs<br />Keeps focus. Gives direction.<br />
    11. 11. Interaction-Based Testing<br />As opposed to state-based testing<br />OOP design principles:<br />Object exposes methods which are the only thing that touch its internal state.<br />Any change in state requires a method call. SO:<br />Just test that the call is made. Mock out all neighboring objects.<br />A true UNIT test. <br />
    12. 12. Is that a Bad thing?<wait for the onslaught><br />HOLD ON!<br />Doesn’t that mean that my tests are tightly coupled with my implementation?<br />
    13. 13. HOW?<br />
    14. 14. How Do I use Rspec (with rails)? <br />
    15. 15. How Do I use Rspec (with rails)?<br />gem install rspecrspec-rails<br />
    16. 16. How Do I use Rspec (with rails)?<br />gem install rspecrspec-rails<br />./script/generate rspec<br />
    17. 17. The Rspec Files<br />
    18. 18. A Word about Factories<br />A easy-to-maintain replacement for fixtures<br />(Finally some code!)<br />More about creating your own strategies at the<br />end of this presentation<br />
    19. 19. spec_helper.rb<br />Loaded at the beginning of ever spec file<br />Put methods that can be used by all specs here.<br />
    20. 20. Examples<br />The equivalent of a unit test in RSpec<br />
    21. 21. The Syntax<br />describe “Unit#something” do<br />before(:each) do<br /> @unit=<br />end<br />it “should return something” do<br /> @unit.something.should == ‘something’<br />end<br />end<br />
    22. 22. The Syntax<br />describe “Unit#something” do<br />before(:each) do<br /> @unit=<br />end<br />it “should return something” do<br /> @unit.something.should == ‘something’<br />end<br />end<br />EXAMPLE<br />
    23. 23. The Syntax<br />describe “Unit#something” do<br />before(:each) do<br /> @unit=<br />end<br />it “should return something” do<br /> @unit.something.should == ‘something’<br />end<br />end<br />
    24. 24. The Syntax<br />context “Unit#something” do<br />before(:each) do<br /> @unit=<br />end<br />specify “should return something” do<br /> @unit.something.should == ‘something’<br />end<br />end<br />
    25. 25. The Syntax<br />describe “Unit#something” do<br />before(:each) do<br /> @unit=<br />end<br />it “should return something” do<br /> @unit.something.should == ‘something’<br />end<br />end<br />
    26. 26. The Syntax<br />describe “Unit#something” do<br />before(:each) do<br /> @unit=<br />end<br />it “should return something” do<br /> @unit.something.should == ‘something’<br />end<br />end<br />
    27. 27. The Syntax<br />describe “Unit#something” do<br />before(:each) do<br /> @unit=<br />end<br />it “should return something” do<br /> @unit.something.should == ‘something’<br />end<br />end<br />
    28. 28. The Syntax<br />describe “Unit#something” do<br />before(:each) do<br /> @unit=<br />end<br />it “should return something” do<br /> @unit.something.should == ‘something’<br />end<br />end<br />
    29. 29. The mocking/stubbing framework<br />object.stub!(:foo => ‘bar’, :one => 1)<br />object.stub!(:foo).and_return(‘bar’)<br />mock_object= mock/mock_model(Klass, espectations= {:foo => ‘bar’})<br /> #=> ‘bar’<br />Tool for Interaction Testing:<br />mock_object.should_receive(:message).exactly(n).times.with(params).and_return(val)<br />Each of the methods in that chain take many different options. Ref: Links<br />Raises error if the message isn’t received & with the parameters specified & with the correct freq.<br />
    30. 30. Mocks Aren’t Stubs<br />Stubs provide canned answers to calls made during the test, usually not responding at all to anything outside what's programmed in for the test. Stubs may also record information about calls, such as an email gateway stub that remembers the messages it 'sent', or maybe only how many messages it 'sent'.<br />Mocks are […] objects pre-programmed with expectations which form a specification of the calls they are expected to receive.<br />-Martin Fowler<br />
    31. 31. Functional Tests(Controller Examples)<br />Isolate controllers from the models(mocks)<br />Big difference from Rails Functional Testing: <br />Also isolate it from the views.<br />Integration is possible with integrate_views<br />
    32. 32. Controller specific Expectations<br />Response Expectations<br />should be_success<br />should render_template<br />should be_redirect<br />should redirect_to<br />response.[assigns|flash|sessions]<br />Routing Expectations<br />route_for(:controller => …, :action => …).should == /…/…/<br />params_from(<br />:get,"/hello/world").should ==<br />{:controller=>"hello”<br /> ,:action => "world"}<br />
    33. 33. View Examples<br />Again<Yawn> Isolation is key.<br /># example<br />article = mock_model(Article) <br />article.should_receive(:author).and_return("J”)<br />article.should_receive(:text).and_return("this is the text of the article") <br />assigns[:article] = article <br />assigns[:articles] = [article]<br /># flash and params are also available<br /># template<br /><% for article in @articles -%> <!-- etc --><br />
    34. 34. View Specific Expectations<br />response.shouldhave_tag<br />#examples<br />response.shouldhave_tag('div#interesting_div‘, contents) <br /># Contents can be Regexp or String<br />response.shouldhave_tag("input[type=?][checked=?]", 'checkbox', 'checked') <br />response.shouldhave_tag('ul') do<br />with_tag('li', 'list item 1') <br />with_tag('li', 'list item 2') <br />with_tag('li', 'list item 3') <br />end<br />
    35. 35. Exercise<br />
    36. 36. My Spec<br />
    37. 37. WHY?<br />
    38. 38. The RSpec Philosophy<br />Clarity over Cleverness<br />Completely isolate the unit under test<br />i.e. Mock Everything<br />
    39. 39. Pros and Cons<br />More descriptive code == more lines of code<br />Not very DRY<br />Tight coupling of test and implementation.<br />Easily understandable tests<br />True unit tests<br />Interoperability with other testing frameworks<br />
    40. 40. Interaction Testing is a Guideline<br />Not a rule<br />Depends on what you are testing.<br />Remember: Usually leads to better OO Design not always better tests.<br />
    41. 41. Good News<br />Rspec doesn’t force IBT on you<br />Write tests that work best for you.<br />
    42. 42. If we’re doing SBT with Rspec.Why not stick to Test::Unit?<br />OPTIONS<br />RSpec is versatile. Can do everything that Test::Unit does and then some.<br />Undoubtedly better for adding new functionality<br />
    43. 43. Why RSpec?<br />RSpec is not just about RSpec. It's about BDD. It's about encouraging conversation about testing and looking at it in different ways. It's about illuminating the design, specification, collaboration and documentation aspects of tests, and thinking of them as executable examples of behaviour. You can do this all without RSpec, but RSpec aims to help with innovations like: <br />strings as example names<br />pending examples<br />nested groups for flexible organization<br />should[_not] + matchers (inspired by hamcrest - a java library)<br />one matcher supports both positive and negative expectations<br />improved failure messages <br />flexible/readable/customizable output formats <br />built-in mocking framework <br />plain text scenarios (now in Cucumber)<br />- David Chelimsky(RSpec lead developer)<br />
    44. 44. More Quotes<br />The problem I have with TDD is that its mindset takes us in a different direction... a wrong direction. – Dave Astels(RSpec Creator)<br />
    45. 45. Thank You!<br />Questions. <br />Pleeeeease!!<br />
    46. 46. Links<br /><br /><br /><br /><br />Why Rspec? []<br />Full List of expectation definition options<br /><br />