[ HackFest.pl 2012] Testing - what for and how

1,657 views

Published on

Published in: Technology, Business
0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
1,657
On SlideShare
0
From Embeds
0
Number of Embeds
67
Actions
Shares
0
Downloads
28
Comments
0
Likes
1
Embeds 0
No embeds

No notes for slide

[ HackFest.pl 2012] Testing - what for and how

  1. 1. TESTINGwhat for and how Michał Czyż @cs3b
  2. 2. selleo.com
  3. 3. http://webout.eu
  4. 4. http://www.worksmartmompreneurs.com/blog/wp-content/uploads/2012/03/url.jpg
  5. 5. ● precise requirements definition● automatic requirements verification● code design● documentation● safety net for code changes● catch errors
  6. 6. http://www.projzilla.com/blog/wp-content/uploads/2011/12/Testing.jpg
  7. 7. http://www.projzilla.com/blog/wp-content/uploads/2011/12/Testing.jpg
  8. 8. ● precise requirements definition● automatic requirements verification● code design● documentation● safety net for code changes● catch errors
  9. 9. TDD
  10. 10. BDD
  11. 11. OUTSIDE-IN
  12. 12. http://pragprog.com/book/achbd/the-rspec-book page#29
  13. 13. http://pragprog.com/book/achbd/the-rspec-book page#29
  14. 14. User perspectivetesting using Ruby
  15. 15. https://twitter.com/#!/moonmaster9000/status/169540724474384384
  16. 16. https://twitter.com/#!/athoshun/statuses/165138347432488962
  17. 17. https://twitter.com/#!/defkode/status/124066265642967040http://www.jackkinsella.ie/2011/09/26/why-bother-with-cucumber-testing.html
  18. 18. http://blog.jonasbandi.net/2010/09/acceptance-vs-integration-tests.html
  19. 19. click "Products"within(table.index) do see :ordered => [ "apache baseball cap", "zomg shirt" ]endclick "admin_products_listing_name_title"within(table.index) do see :ordered => [ "zomg shirt", "apache baseball cap"]end
  20. 20. click "Orders"within(table#listing_orders, :row => 1) do click_link "R100"endclick "Payments"within(#payment_status) do see("Payment: balance due")endwithin(:cell =>[2,2]) { see "$39.98" }within(:cell =>[2,3]) { see "Credit Card" }within(:cell =>[2,4]) { see "pending" }
  21. 21. click
  22. 22. click Administrations, Products,click :and_dismiss => Deleteclick :and_accept => Deleteclick :image => OKclick :element => "#some_div"
  23. 23. fill_in
  24. 24. fill_in www.selleo.com => Linkfill_in www.selleo.com => Link Selleo => Company, Poland => Country
  25. 25. fill_in :check => Remember mefill_in :check => [ Red, Green, Grey ]
  26. 26. fill_in :uncheck => Remember mefill_in :uncheck => [ Red, Green, Grey ]
  27. 27. fill_in :choose => Femalefill_in :choose => [ Europe, Poland ]
  28. 28. fill_in :select => { Poland => Countries }fill_in :select => { Poland => Countries, Silesia => Provinces }
  29. 29. fill_in :unselect => { Poland => Countries }fill_in :unselect => { Poland => Countries, Silesia => Provinces }
  30. 30. fill_in :attach => { me.png => Avatar}fill_in :attach => { me.png => Avatar, selleo.png => Company Logo }
  31. 31. # spec_helper.rbKameleon.configure do |c| c.assets_dir = (...)/fixtures/assetsend
  32. 32. see
  33. 33. see www.selleo.com,see one, another piece of text, and another one
  34. 34. see :link => Wrocloverbsee :link => { Wrocloverb => http://wrocloverb.com }see :links => { Wrocloverb => http://wrocloverb.com, Selleo => http://www.selleo.com }
  35. 35. see :image => OKsee :image => icon_ok.pngsee :images => [ completed, approved ]
  36. 36. see Ruby => First Namesee Wisła => City, Silesia => Province
  37. 37. see :field => Emailsee :fields => [Email, City, Street ]
  38. 38. see :empty => Last Namesee :empty => [ Last Name, City ]
  39. 39. see :checked => Remember mesee :checked => [ Newsletter, Remember me ]
  40. 40. see :unchecked => Remember mesee :unchecked => [ Newsletter, Remember me ]
  41. 41. see :selected => { Poland => Countries }see :selected => { Poland => Countries, Silesia => Provinces }
  42. 42. see :selected => { [ Red, Green, Orange ] => Colors }
  43. 43. see :unselected => { Poland => Countries }see :unselected => { Poland => Countries, Silesia => Provinces }
  44. 44. see :unselected => { [ Red, Green, Orange ] => Colors }
  45. 45. see :ordered => [ Bart, Tom, Anette ]
  46. 46. see 5 => ".element"see 3 => :menu_itemsee 5 => [:xpath, //div[@class="element"] ]
  47. 47. not_see
  48. 48. not_see phpnot_see java, c#, .net
  49. 49. not_see :field => Emailnot_see :fields => [ Email, City, Street ]
  50. 50. not_see :link => Wrocloverbnot_see :link => { Wrocloverb => http://wrocloverb.com }not_see :links => [ Wrocloverb, Selleo ]
  51. 51. not_see :image => OKnot_see :image => ok.pngnot_see :images => [ OK, rails.png ]
  52. 52. act_as
  53. 53. visit(/)act_as(:default) do click Productsend
  54. 54. visit(/)create_session(:user)visit(/login)act_as(:default) do not_see :field => Emailendact_as(:user)see :fields => [ Email, Password ]
  55. 55. http://s1.desktopia.net/wp-content/uploads/walls/thumbs/Funny-Chameleon-575x359.jpg
  56. 56. click_link "Products"within(table.index tr:nth-child(2)) { page.should have_content("apache baseball cap") }within(table.index tr:nth-child(3)) { page.should have_content("zomg shirt") }click_link "admin_products_listing_name_title"within(table.index tr:nth-child(2)) { page.should have_content("zomg shirt") }within(table.index tr:nth-child(3)) { page.should have_content("apache baseball cap") }https://github.com/spree/spree/blob/master/core/spec/requests/admin/products/products_spec.rb#L22
  57. 57. click "Products"within(table.index) do see :ordered => [ "apache baseball cap", "zomg shirt" ]endclick "admin_products_listing_name_title"within(table.index) do see :ordered => [ "zomg shirt", "apache baseball cap"]end
  58. 58. click_link "Products"click_link "admin_new_product"fill_in "product_name", :with => "Baseball Cap"fill_in "product_sku", :with => "B100"fill_in "product_price", :with => "100"fill_in "product_available_on", :with => "2012/01/24"select "Size", :from => "Prototype"check "Large"click_button "Create"page.should have_content("successfullycreated!")https://github.com/spree/spree/blob/master/core/spec/requests/admin/products/products_spec.rb#L77
  59. 59. click "Products", "admin_new_product"fill_in "Baseball Cap" => "product_name", "B100" => "product_sku", "100" => "product_price", "2012/01/24" => "product_available_on", :select => { "Size" => "Prototype" }, :check => "Large"click "Create"see "successfully created!"
  60. 60. within(:css, table.index tr:nth-child(2)) { click_link "Edit" }fill_in "adjustment_amount", :with => "99"fill_in "adjustment_label", :with => "rebate 99"click_button "Continue"page.should have_content("successfully updated!")page.should have_content("rebate 99")page.should have_content("$99.00")https://github.com/spree/spree/blob/master/core/spec/requests/admin/orders/adjustments_spec.rb#L48
  61. 61. within(:row => 2) { click "Edit" }fill_in 99 => "adjustment_amount", "rebate 99" => "adjustment_label"click "Continue"see "successfully updated!", "rebate 99", "$99.00"
  62. 62. click_link "Orders"within(table#listing_orders tbody tr:nth-child(1)) { click_link "R100" }click_link "Payments"within(#payment_status) { page.shouldhave_content("Payment: balance due") }find(table.index tbody tr:nth-child(2) td:nth-child(2)).text.should == "$39.98"find(table.index tbody tr:nth-child(2) td:nth-child(3)).text.should == "Credit Card"find(table.index tbody tr:nth-child(2) td:nth-child(4)).text.should == "pending"https://github.com/spree/spree/blob/master/core/spec/requests/admin/orders/payments_spec.rb#L32
  63. 63. click "Orders"within(table#listing_orders, :row => 1) do click_link "R100"endclick "Payments"within(#payment_status) do see("Payment: balance due")endwithin(:cell =>[2,2]) { see "$39.98" }within(:cell =>[2,3]) { see "Credit Card" }within(:cell =>[2,4]) { see "pending" }
  64. 64. DEMO inspired by a case takenfrom a production system
  65. 65. create_session(:user)sign_in_as(:user)create_session(:admin)sign_in_as(:admin)
  66. 66. act_as(:user) do not_see IS OPEN, IS CLOSED within(:right_column) do not_see Submit a proposal, Submit endend
  67. 67. act_as(:admin) do within(:menu) { click Set Contest } fill_in S vs C => Name, 2012-01-19 08:00:00 => starts at, 2012-01-20 08:00:00 => ends at click Create Contest see Contest was successfully createdend
  68. 68. Timecop.travel(2012, 1, 19, 8, 59, 55) do act_as(:user) do refresh_page see IS CLOSED sleep 10 not_see IS CLOSED see IS OPEN endend
  69. 69. Timecop.travel(2012, 1, 19, 9, 1, 1) do act_as(:user) do refresh_page %w(ruby ... haml).each do |content| fill_in content => proposal_content click Submit end end
  70. 70. act_as(:admin) do click Sticker proposals, Load more %w(ruby ... html).each do |c| within(:proposal_with_content => c) do click favorite end endend
  71. 71. act_as(:user) do refresh_page %w(...).each_with_index do |c, r| within(:proposal_with_content => c) do click "Rate #{r+1} out of 5" end endend
  72. 72. act_as(:user) do %w(ruby coffescript).each do |c| within(:proposal_with_content => c) do click Comment fill_in "sample text #{c}" => body click Create comment end endend
  73. 73. Timecop.travel(2012, 1, 20, 11, 10, 10) do act_as(:admin) do refresh_page click Load more %w(html python).each do |c| within(:proposal_with_content => c) do click choose end end end
  74. 74. act_as(:user) do refresh_page click Gallery within(:ordered_list) do see *(%w(html python)) not_see *(%w(ruby ... coffescript)) endend
  75. 75. act_as(:admin) do click Gallery, Add new production picture fill_in Sample title for picture => Title, :attach => {pict.jpg => Image} click Create Gallery imageend
  76. 76. act_as(:user) do click Gallery fill_in :select => {S vs C => contest_id} within(:gallery_list) do see :image => Thumb_pict endend
  77. 77. act_as(:admin) do click Add new contest sticker fill_in Sample title for picture => Title, :attach => {pict2.jpg => Image} click Create Gallery imageend
  78. 78. act_as(:user) do click Gallery fill_in :select => {S vs C => contest_id} within(:gallery_list) do see :image => Thumb_pict2 endend
  79. 79. http://2.bp.blogspot.com/_bVtGlUaW-tA/TMOUvmYXzHI/AAAAAAAAP90/SR5yHHWydN4/s1600/Mech_chameleon_by_tommaso_sanguigni.jpg
  80. 80. # gemfilegem kameleon, >= 0.2.0.alpha.2gem headless# spec_helper.rbrequire kameleonrequire kameleon/ext/rspec/all
  81. 81. # orrequire kameleon/ext/rspec/dsl# optional# .../rspec/garbage_collector# .../rspec/headless
  82. 82. SHARED DB CONNECTIONexample: lib/kameleon/ext/active_record/● shared_single_connection.rb● shared_single_connection_with_spork.rb
  83. 83. HEADLESSRSpec.configure do |config| config.before(:suite) do @headless = Headless.new(:display => 100) @headless.start end config.after(:suite) do @headless.stop if defined?(@headless) endendrequire kameleon/ext/rspec/headless
  84. 84. RIPL config.after(:each) do if exception = example.instance_variable_get(:@exception) Ripl.start :binding => binding end endexample: lib/kameleon/utils/debug_console.rb
  85. 85. FAKE DATA IN ACCEPTANCE AND INTEGRATION TESTS
  86. 86. DATABASE
  87. 87. FIXTURES# fernitures.ymlcouch: name: Couch price: 399.99 manufacturer: lazyboy categories: furnituretv_stand: name: TV Stand price: 149.95 manufacturer: highdeph categories: furniture, electronics# categories.ymlfurniture: name: Furnitureelectronics: name: Electronics
  88. 88. FIXTURES---- PostgreSQL database dump--SET statement_timeout = 0;SET client_encoding = UTF8;SET standard_conforming_strings = on;SET check_function_bodies = false;SET client_min_messages = warning;
  89. 89. FACTORIES10.times do |i| banner = BannerMessage.new :content => "text_#{i}" banner.origin_ip = "127.#{i+1}.#{i}.#{i}" banner.save! rand(6).times do |v| vote = banner.votes.build vote.origin_ip = "127.0.0.#{v}" vote.cookies = {vote.banner_message_id.to_s => Time.now.to_s} vote.save! endend
  90. 90. FACTORIESFactoryGirl.define do factory :comment do sequence(:body) { |n| "this is #{n} comment!" } banner_message sequence(:origin_ip) { |n| "127.0.0.#{n}" } user endend###10.times { Factory.create(:comment) }
  91. 91. SERVICES
  92. 92. VCR + WEB MOCKVCR.configure do |c| c.cassette_library_dir = spec/fixtures/vcr_cassettes c.hook_into :webmock c.default_cassette_options = { :record => :new_episodes }end
  93. 93. VCR + WEB MOCKcontext "passing authentication process", :status => :done do use_vcr_cassette authorization_pass before(:each) do get /, nil, { HTTP_AUTHORIZATION => {"domain" => "selleo2", "email" => "m.czyz@selleo.com", "token" => "xK1KPKCcP3v6VvTkhDogzI"}.to_json } end it { response.code.should == "200" } it message do ...
  94. 94. VCR + WEB MOCK---recorded_with: VCR 2.0.0http_interactions:- request: method: get uri: https://someapp.com/api/v1/users/current body: string: "" headers: ... Authorization: - Basic bSnl6QHNlbjb20vdG9rZW46eS1BL User-Agent: - Some Ruby Client 0.1.0
  95. 95. VCR + WEB MOCKresponse: status: code: 200 message: OK headers: Content-Type: - application/json; charset=utf-8 Server: - nginx/0.8.53 .... Connection: - keep-alive body: string: "{"name":"Selleo","locale_id":null,"pho":"wow"}" http_version:recorded_at: Mon, 09 Apr 2012 11:32:23 GMT
  96. 96. VCR + WEB MOCKresponse: status: code: 200 message: OK headers: Content-Type: - application/json; charset=utf-8 Server: - nginx/0.8.53 .... Connection: - keep-alive body: string: "{"name":"Selleo","locale_id":null,"pho":"wow"}" http_version:recorded_at: Mon, 09 Apr 2012 11:32:23 GMT
  97. 97. META-DATA
  98. 98. context "passing auth", :status => :done do use_vcr_cassette authorization_pass ...end
  99. 99. #::: page: sign_in#::: wireframe: http://some_urlcontext "passing auth", :status => :done do use_vcr_cassette authorization_pass ...end
  100. 100. INTEGRATION TESTS
  101. 101. http://blog.jonasbandi.net/2010/09/acceptance-vs-integration-tests.html
  102. 102. INTEGRATION TESTdescribe "fill in" do before(:each) { visit(/form_elements) } context "single value in field" do it "text" do see :empty => [ sampleEmptyInput, textarea2] fill_in Value for sampleEmtyInput => sampleEmptyInput, Value for textarea2 => textarea2 see Value for textarea2 => textarea2, Value for sampleEmtyInput => sampleEmptyInput end it "checkbox" do see :unchecked => Sample unchecked checkbox fill_in :check => Sample unchecked checkbox see :checked => Sample unchecked checkbox fill_in :uncheck => Sample checked checkbox see :unchecked => Sample checked checkbox end
  103. 103. INTEGRATION TESTdescribe order do before(:each) { visit(/special_elements) } it should see text in proper order do see :ordered => [Michal Czyz, Tomasz Bak, Rafal Bromirski] end context raise error do it different order do expect do see :ordered => [Tomasz Bak, Michal Czyz, Rafal Bromirski] end.to raise_error(RSpec::Expectations::ExpectationNotMetError) end it not all elements present do expect do see :ordered => [Michal Czyz, Lukas Bak, Rafal Bromirski] end.to raise_error(RSpec::Expectations::ExpectationNotMetError) end endend
  104. 104. INTEGRATION TESTbefore(:each) do post "/users", { :user => { :name => "Wookie 5", :email => "wookie5@selleo.com", :roles => 4, "is_verified" => true, :groups => [20188052, 20180893] } }, SelleoSomeApi.headersendit { response.status.should == 201 }subject do JSON.parse(response.body)endit { subject["id"].should be_a(Fixnum) }it { should include "email" => "wookie5@selleo.com" }it { should include "name" => "Wookie 5" }it { should include "roles" => 4 }it { should include "is_active" => true }it { should include "is_verified" => "true" }
  105. 105. UNIT TESTS
  106. 106. UNIT TESTdescribe "PARSING" do before(:each) do subject { CucumberFM::Feature.new(some_path) } subject.stub(:raw).and_return(FEATURE_CONTENT) cfm = mock(:cfm) filter = CucumberFM::TagFilter.new() cfm.stub(:filter).and_return(filter) subject.stub(:cfm).and_return(cfm) end it "should parse feature info" do CucumberFM::FE::Info.should_receive(:new).with(subject, INFO_CONTENT) subject.info end it "should parse background" do CucumberFM::FE::Background.should_receive(:new).with(subject, BAC..._C) subject.background end
  107. 107. UNIT TESTdescribe CucumberFM::FeatureElement::Info do before(:all) do raw = <<EOF #{@comment_1 = "# some comment"} @tag @mc Feature: #{@title = "Tag filter"}EOF feature = CucumberFM::Feature.new(fake_path) @info = CucumberFM::FeatureElement::Info.new(feature, raw) end it "should parse tags" do @info.tags.should == %w(@tag @mc) end it "should parse comments lines" do CucumberFM::FE::Comment.should_receive(:new).with(@info, @comment_1) CucumberFM::FE::Comment.should_receive(:new).with(@info, @comment_2) @info.should have(2).comments end
  108. 108. UNIT vsINTEGRATION
  109. 109. http://www.codingthearchitecture.com/images/20120412-sketches.jpg
  110. 110. PERFORMANCE TESTS
  111. 111. http://2.bp.blogspot.com/-yR4off2JRt0/TzZEOolbm5I/AAAAAAAAB_Q/Sl7UKjVl9Cw/s400/Snail%2Bon%2Bturtle%2Bfast.jpg
  112. 112. http://www.projzilla.com/blog/wp-content/uploads/2011/12/Testing.jpg
  113. 113. LOADTESTS
  114. 114. http://www.funtim.com/wp-content/uploads/2009/01/indian-funny-pic.jpg
  115. 115. http://www.projzilla.com/blog/wp-content/uploads/2011/12/Testing.jpg
  116. 116. SECURITY TESTS
  117. 117. http://www.penetration-testing-group.co.uk/penetration-testing.jpg
  118. 118. http://www.projzilla.com/blog/wp-content/uploads/2011/12/Testing.jpg
  119. 119. STATICANALYSIS
  120. 120. http://metric-fu.rubyforge.org/reek.gif
  121. 121. CONTINUOUSINTEGRATION
  122. 122. http://www.jetbrains.com/teamcity/features/index.html
  123. 123. http://beta.travis-ci.com/?lrRef=rk8v2
  124. 124. http://www.worksmartmompreneurs.com/blog/wp-content/uploads/2012/03/url.jpg
  125. 125. ● precise requirements definition● automatic requirements verification● code design● documentation● safety net for code changes● catch errors
  126. 126. LINKSRSPEC ● http://pragprog.com/book/achbd/the-rspec-book ● https://www.relishapp.com/rspecCAPYBARA ● https://github.com/jnicklas/capybaraXPATH ● http://www.w3.org/TR/xpath/ ● https://addons.mozilla.org/en-US/firefox/addon/firepath/SELENIUM ● http://seleniumhq.org/docs/WEBKIT ● https://github.com/thoughtbot/capybara-webkitKAMELEON● https://github.com/cs3b/kame leon
  127. 127. THANKS :-)questions ? http://selleo.com/people/michal-czyz http://cs3b.com

×