Bdd. Why? How?

1,822 views

Published on

Published in: Technology, Health & Medicine
0 Comments
2 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
1,822
On SlideShare
0
From Embeds
0
Number of Embeds
27
Actions
Shares
0
Downloads
23
Comments
0
Likes
2
Embeds 0
No embeds

No notes for slide

Bdd. Why? How?

  1. 1. BDD Why? How? by Gregory Man
  2. 2. Server Side (Ruby on Rails)
  3. 3. Online Game Server Side
  4. 4. and... scalability problems Tanks to Amazon EC2 :)
  5. 5. Podcaster
  6. 6. Ruby NoName Podcast only in russian... sorry. 3rd place in the rpod.ru TOP-20 (biggest russian podcast aggregator)
  7. 7. But, it all doesn't matter...
  8. 8. I'm a BDD Freak! $ rake stats (on my last 3 projects) Code to Test Ratio: 1:1.9 Code to Test Ratio: 1:2.9 Code to Test Ratio: 1:3.5
  9. 9. Why!?! • so many fucking code in u specs!!! • so many time to write specs!!! • My code is working without them just fine.
  10. 10. Coz.... • I don't believe my code is working, I need proof. • I don't believe my code didn't break anything. • I will forget what my code does in 2 days. • I want to sleep well at night. At least when I sleep alone.
  11. 11. BDD == TDD ?
  12. 12. BDD != TDD
  13. 13. Don’t write tests.
  14. 14. Explain what your code should do! describe 'BDD "why and how?" talk' do   before(:each) do     @presentation = Presentation.new(:subject => :bdd)   end     it "should be less then 15 minutes" do     @presentation.length.should_be < 15.minutes   end     it "should include RSpec topic" do     @presentation.topics.should include("RSpec")   end      it "should include Cucumber topic" do     @presentation.topics.should include("Cucumber")   end end
  15. 15. BDD == write specs first?
  16. 16. BDD =~ write specs first
  17. 17. BUT!
  18. 18. BDD isn’t about testing
  19. 19. BDD is about design
  20. 20. Design is PROCESS not a phase.
  21. 21. Code life-cycle http://www.flickr.com/photos/foxtongue/ http://www.flickr.com/photos/mauricedb/
  22. 22. Birth
  23. 23. Maybe not BDD, but...
  24. 24. Draw mockups first
  25. 25. Cucumber http://www.flickr.com/photos/84615345@N00/
  26. 26. tell a story Feature: Podcasts list   In order to be tuned   As a podcast listener   I want to see the podcasts list     Scenario: Podcasts list     Given I have podcast titled "Pilot Release"     And I have podcast titled "Second One"     And I have podcast titled "Third as Expected"       When I go to the podcasts list       Then I should see "Pilot Release"     And I should see "Second One"     And I should see "Third as Expected"     Scenario: Podcasts list null screen     Given I have no podcasts     When I go to the podcasts list     Then I should see nice podcasts list null screen     Scenario: Podcasts should be numbered     Given I have a couple of podcasts     When I go to the podcasts list     Then I should see podcasts are numbered  
  27. 27. in any language ‫תכונה: חיבור‬ Функционал: Сложение чисел ‫  כדי למנוע טעויות טפשיות‬   Чтобы не складывать в уме ‫  בתור בור מתמטי‬   Все, у кого с этим туго ‫  אני רוצה שיגידו לי את הסכום של שני מספרים‬   Хотят автоматическое сложение целых чисел     ‫  תבנית תרחיש: חבר שני מספרים‬   Сценарий: Сложение двух целых чисел ‫    בהינתן שהזנתי >קלט_1< למחשבון‬     Допустим я ввожу число 50 ‫    וגם שהזנתי >קלט_2< למחשבון‬     И затем ввожу число 70 <‫    כאשר אני לוחץ על >כפתור‬     Если я нажимаю "+" <‫    אז התוצאה על המסך צריכה להיות >פלט‬     То результатом должно быть число 120 ‫ﺧﺎﺻﻴﺔ: ﺍﳉﻤﻊ‬ Feature: Addition ‫  ﻣﻦ ﺍﺟﻞ ﲡﻨﺐ ﺍﻷﺧﻄﺎﺀ ﺍﻟﺴﺨﻴﻔﺔ‬   In order to avoid silly mistakes ‫  ﻛﺸﺨﺺ ﻏﺒﻲ ﻓﻲ ﺍﻟﺮﻳﺎﺿﻴﺎﺕ‬   As a math idiot ‫  ﺍﺭﻳﺪ ﻣﻌﺮﻓﺔ ﻧﺎﰋ ﺟﻤﻊ ﻋﺪﺩﻳﻦ‬   I want to be told the sum of two numbers     ‫  ﺳﻴﻨﺎﺭﻳﻮ ﻣﺨﻄﻂ: ﺟﻤﻊ ﻋﺪﺩﻳﻦ‬   Scenario Outline: Add two numbers ‫< ﻓﻲ ﺍﻵﻟﺔ ﺍﳊﺎﺳﺒﺔ‬input_1> ‫    ﺑﻔﺮﺽ ﻛﺘﺎﺑﺔ‬     Given I have entered <input_1> into the calculator ‫< ﻓﻲ ﺍﻵﻟﺔ ﺍﳊﺎﺳﺒﺔ‬input_2> ‫    ﻭ ﻛﺘﺎﺑﺔ‬     And I have entered <input_2> into the calculator <button> ‫    ﻣﺘﻰ ﻳﺘﻢ ﺍﻟﻀﻐﻂ ﻋﻠﻰ‬     When I press <button> ‫< ﻋﻠﻰ ﺍﻟﺸﺎﺷﺔ‬output> ‫    ﺍﺫﺍً ﻳﻈﻬﺮ‬     Then the result should be <output> on the screen  
  28. 28. now is magic time! $ rake features
  29. 29. ok, ok no magic here. U need to do some work to get this work.
  30. 30. Just old good regexp Given I have podcast titled "Pilot Release" Given /^I have podcast titled "([^"]*)"$/ do |title|   Factory(:podcast, :title => title) end When I go to the podcasts list When /^I go to (.+)$/ do |page_name|   visit path_to(page_name) end module NavigationHelpers   def path_to(page_name)     case page_name       when /the homepage/       '/'     when /the podcasts list/       podcasts_path     else       raise "Can't find mapping from "#{page_name}" to a path.n" +         "Now, go and add a mapping in #{__FILE__}"     end   end end
  31. 31. and RSpec assertions Then I should see "Pilot Release" Then /^I should see "([^"]*)"$/ do |text|   response.should contain(text) end Then I should see nice Then /^I should see nice podcasts list null screen$/ do podcasts list null screen   response.should have_tag('.null_content') end
  32. 32. Work not only with rails • Pure Ruby • Merb • Sinatra • more.... not only for pure html • AJAX • FLEX • more....
  33. 33. Learn more: • http://cukes.info/ • http://onrails.org/articles/category/flex • google it!
  34. 34. Describe your code with RSpec and a little bit shoulda
  35. 35. Cucumber - user’s point of view RSpec - developer’s point of view
  36. 36. Models describe Podcast do    describe "performing operations requiring its number to be updated" do     before do       @last_podcast_number = 5         Podcast.delete_all       @last_podcast_number.times do |idx|         Factory(:podcast, :title => "Podcast Numbered #{idx + 1}")       end     end       it "should automatically set number" do       podcast = Factory(:podcast)       podcast.number.should == @last_podcast_number + 1     end       it "should set correct number if any other podcast has been removed before" do       broken_podcast = Factory(:podcast)       broken_podcast.destroy       podcast = Factory(:podcast)       podcast.number.should == @last_podcast_number + 1     end       it "should correct podcast numbers on delete" do       podcast = Factory(:podcast)       lambda {         Podcast.find(:first, :offset => @last_podcast_number/2).destroy # remove in around a middle         podcast.reload       }.should change(podcast, :number).by(-1)     end   end end
  37. 37. Shoulda matchers. Why? — shorter describe Podcast do VS describe Podcast do   it { should validate_presence_of(:title) }   describe "validations" do   it { should validate_presence_of(:asset_link) }     it "should be invalid without title" do end       podcast = Factory.build(:podcast, :title => nil)       podcast.should_not be_valid       podcast.should have(1).error_on(:title)     end          it "should be invalid without asset link" do       podcast = Factory.build(:podcast, :asset_link => nil)       podcast.should_not be_valid       podcast.should have(1).error_on(:asset_link)     end   end end
  38. 38. Controllers describe PodcastsController do   describe "handling GET /podcasts" do       before do       @podcast = mock_model(Podcast)       Podcast.stub!(:find).and_return([@podcast])     end       it "should be successful" do       get :index       response.should be_success     end       it "should render index template" do       get :index       response.should render_template('index')     end       it "should find all podcasts" do       Podcast.should_receive(:find).with(:all).and_return([@podcast])       get :index     end       it "should assign the found podcasts for the view" do       get :index       assigns[:podcasts].should == [@podcast]     end   end end
  39. 39. Mocks vs Stubs describe PodcastsController do   describe "handling GET /podcasts" do       before do       @podcast = mock_model(Podcast) Stub       Podcast.stub!(:find).and_return([@podcast])     end       it "should be successful" do       get :index       response.should be_success     end       it "should render index template" do Mock       get :index       response.should render_template('index')     end       it "should find all podcasts" do       Podcast.should_receive(:find).with(:all).and_return([@podcast])       get :index     end       it "should assign the found podcasts for the view" do       get :index       assigns[:podcasts].should == [@podcast]     end   end end
  40. 40. Views The question is...
  41. 41. Views The question is... Should I test views? to test or not to test?
  42. 42. Only important things
  43. 43. Some tips • Don’t forget about MVC • don’t DRY too hard • Try writing specs first • Test behavior, not implementation
  44. 44. Life
  45. 45. AutoSpec Should work on windows (not promise anything)
  46. 46. Continuous Integration with Integrity
  47. 47. Web Interface
  48. 48. Notifications via • Email • Campfire • IRC • Jabber • Twitter • Basecamp • Yammer
  49. 49. Death
  50. 50. Do I need to teach u how to delete code?!
  51. 51. Questions?

×