RSpec for Practical Rubyist

RSpec for Practical Rubyist

@ RubyConfTaiwan 2015

771951f55ed37335f238e1a80dfda9cd?s=128

Juanito Fatas

September 11, 2015
Tweet

Transcript

  1. 1.

    RSPEC FOR THE PRACTICAL RUBYIST EXPLAINING SIMPLY AND QUICKLY ALL

    THE ELEMENTS OF CONTROLLER, MODEL, VIEW, HELPER, INTEGRATION, FEATURE WITHout ANSWERS TO PROBLEMS
  2. 3.

    rubytaiwan/taipei Things to know about Taipei put together by Ruby

    Taiwan Community Inspired from RubySG/Singapore
  3. 9.
  4. 10.
  5. 11.
  6. 14.
  7. 22.

    %

  8. 23.
  9. 33.

  10. 35.
  11. 39.
  12. 40.

    RSPEC FOR THE PRACTICAL RUBYIST EXPLAINING SIMPLY AND QUICKLY ALL

    THE ELEMENTS OF CONTROLLER, MODEL, VIEW, HELPER, INTEGRATION, FEATURE WITHout ANSWERS TO PROBLEMS
  13. 43.
  14. 48.

    correctness quality buying time for the future finding regressions save

    repeated labor gives you confidence easy refactoring perfect bug report live documentation drive your implementation automation is win ✨
  15. 51.
  16. 54.

    A professional developer should be able to work in either

    one of these because they essentially do the same thing: test your code. — Dr.Tenderlove “ http://tenderlovemaking.com/2015/01/23/my-experience-with-minitest-and-rspec.html
  17. 55.

    class Something < Minitest::Test def test_works assert_equal 11, 10 end

    def test_really_works assert_equal 11, 11 end end (Unit)Test
  18. 57.

    describe "something" do it "works" do expect(11).to equal(10) end it

    "really works" do expect(11).to equal(11) end end Spec(ification)
  19. 58.

    Test cases are describe with description string / actual object

    and a block of tests Tests are it with description string and the body of test (block)
  20. 59.
  21. 64.
  22. 66.
  23. 71.

    Computer science is a terrible name for this business. First

    of all, it's not a science. It might be engineering or it might be art, but we'll actually see that computer so-called science actually has a lot in common with magic.— Hal Abelson “ https://youtu.be/2Op3QLzMgSY?t=27s
  24. 76.

    describe it expect to a series of tests is a

    test an actual object match something
  25. 128.
  26. 131.

    eq eql equal be be_* match be_within start_with end_with be_instance_of

    be_kind_of respond_to raise_error throw_symbol include match_array contain_exactly cover change satisfy output yield_* https://www.relishapp.com/rspec/rspec-expectations/docs/built-in-matchers "1*
  27. 132.

    expect { code }.to raise_error(error, message) expect { post :create

    } .to raise_error( ActiveRecord::RecordInvalid, "Validation failed: name can't be blank" ) raise_error matcher
  28. 133.

    expect { code }.to change { something }.by(value) def do_request

    post :create, user: params end expect { do_request }.to change { User.count }.by(1) change matcher
  29. 135.
  30. 140.

    describe Baz let(:foo) { "bar" } it "…" do ...

    end end foo will be available in it blocks under the same scope!
  31. 141.

    let(:foo) { sleep 42 } it "…" do ... end

    Finished in 0.04424 seconds it "…" do ... end
  32. 142.

    let(:foo) { sleep 42 } it "…" do foo end

    Finished in 42.03924 seconds it "…" do ... end
  33. 143.

    let!(:foo) { sleep 42 } it "…" do ... end

    Finished in 42.03924 seconds it "…" do ... end
  34. 152.
  35. 153.
  36. 166.

    context "stub and mock" do describe "stub" do it "won't

    verify" do allow(User).to receive(:new) # User.new end end describe "mock" do it "will verify" do expect(User).to receive(:new) # User.new end end end
  37. 167.

    context "stub and mock" do describe "stub" do it "won't

    verify" do allow(User).to receive(:new) # User.new end end describe "mock" do it "will verify" do expect(User).to receive(:new) # User.new end end end Stub
  38. 168.

    context "stub and mock" do describe "stub" do it "won't

    verify" do allow(User).to receive(:new) # User.new end end describe "mock" do it "will verify" do expect(User).to receive(:new) # User.new end end end Mock
  39. 169.

    context "stub and mock" do describe "stub" do it "won't

    verify" do allow(User).to receive(:new) # User.new end end describe "mock" do it "will verify" do expect(User).to receive(:new) # User.new end end end Failure/Error: expect(User).to receive(:new) Mock
  40. 171.

    context "stub and mock" do describe "stub" do it "stub

    and verify" do allow(User).to receive(:new) User.new expect(User).to have_received(:new) end end end
  41. 172.

    context "stub and mock" do describe "stub" do it "won't

    verify" do allow(User).to receive(:new) User.new expect(User).to have_received(:new) end end end Strategy Spaces
  42. 174.

    setup exercise verify teardown everything we need the real work

    our expectations back to original state
  43. 180.

    before { user = User.new(password: "passw0rd") } it "should encrypt

    password" do user.save expect(user.encrypted_password).not_to eq nil end Put together
  44. 181.

    it "should encrypt password" do user = User.new(password: "passw0rd") user.save

    expect(user.encrypted_password).not_to eq nil end Strategy Spaces
  45. 182.

    Spy

  46. 197.
  47. 200.
  48. 205.
  49. 206.

    Fixture # spec/fixtures/users.yml juanitofatas: name: JuanitoFatas email: juanito@jollygoodcode.com # spec/rails_helper.rb

    RSpec.configure do |config| config.fixture_path = "#{::Rails.root}/spec/fixtures" config.use_transactional_fixtures = true end # under describe or context users :juanitofatas # => #<User:0x1234 name: "JuanitoFatas" email:"…">
  50. 213.

    RSpec.configure do |config| config.include FactoryGirl::Syntax::Methods end $PO H create(:user) instead

    of FactoryGirl.create(:user) https://github.com/thoughtbot/factory_girl/blob/master/GETTING_STARTED.md
  51. 222.
  52. 226.

    Test like how user use it Use real database records

    Don’t mock or stub objects External Service can stub 5JQ
  53. 235.

    &YBN QMF feature "Auth" do given { ... } background

    { ... } scenario "show name" do ... end end
  54. 237.

    RSpec.feature "…" do end Capybara API will be available in

    here http://www.rubydoc.info/github/jnicklas/capybara/master#The_DSL
  55. 238.

    "1* page visit current_path click_on find fill_in choose check select

    attach_file https://github.com/jnicklas/capybara#the-dsl
  56. 240.

    &YBN QMF feature "Sign In" do scenario "works" do visit

    root_path click_on "Sign In" fill_in "login", with: "JuanitoFatas" fill_in "password", with: "1passw0rd" click_on "Sign In" end end
  57. 241.

    &YBN QMF feature "Auth" do scenario "show name" do create(:user,

    name: "Juan") sign_in_as(user) expect(page).to have_content("Juan") end end
  58. 242.

    &YBN QMF feature "Vote" do scenario "upvote" do create(:user, name:

    "Juan") sign_in_as(user) expect(page).to have_content("Votes 0") find("upvote").click expect(page).to have_content("Votes 1") end end
  59. 243.
  60. 252.

    require "rails_helper" RSpec.describe ShopsController do describe "#index" do ... end

    describe "#new" do ... end describe "#create" do ... end … $POWFOUJPO
  61. 253.

    describe "#show" do ... end describe "#edit" do ... end

    describe "#update" do ... end describe "#destroy" do ... end end $POWFOUJPO
  62. 254.

    5JQ Ordering should be the same as your actions in

    controller index new create show edit update destroy
  63. 256.

    params request response session flash cookie "1* get post patch

    put head delete ActionController::TestCase
  64. 259.

    RSpec.describe HomeController do describe "#index" do def do_request get :index

    end it "works" do do_request expect(response).to be_success end end end JOEFY
  65. 260.

    describe HomeController do describe "#index" do def do_request get :index

    end it "works" do do_request expect(response).to be_success end end end &YBN QMF same scope
  66. 263.

    describe "#index" do def do_request get :index end before {

    do_request } it { expect(response).to be_success } end JOEFY
  67. 264.

    describe "#new" do def do_request get :new end before {

    do_request } it { expect(response).to be_success } end OFX
  68. 265.

    describe "#create" do def do_request post :create, thing: params end

    context "success" do ... end context "failure" do ... end end DSFBUF
  69. 266.

    describe "#show" do let(:thing) { create(:thing) } def do_request get

    :show, id: thing end before { do_request } it { expect(response).to be_success } end TIPX
  70. 267.

    FEJU describe "#edit" do let(:thing) { create(:thing) } def do_request

    get :edit, id: thing.id end before { do_request } it { expect(response).to be_success } end
  71. 268.

    describe "#update" do let(:thing) { create(:thing) } def do_request patch

    :update, id: thing.id, thing: params end before { do_request } context "success" do ... end context "failure" do ... end end VQEBUF
  72. 269.

    describe "#destroy" do let!(:thing) { create(:thing) } def do_request delete

    :destroy, id: thing.id end it "redirects" do expect { do_request }.to change(Thing, :count).by(-1) expect(response).to redirect_to things_path end end EFTUSPZ
  73. 271.

    3BJMT post :show, { id: 1 }, { user_id: 1

    }, { notice: "flash message" }
  74. 272.

    3BJMT post :show, { id: 1 }, {}, { notice:

    "flash message" } params session flash
  75. 273.

    3BJMT post :show, { shop_id: 1 }, {}, { notice:

    "flash message" } params session flash
  76. 274.

    3BJMT post :show, params: { shop_id: 1 }, session: {

    user_id: 1 }, flash: { notice: "flash message" } Rails 5 Switch to Keyword Arguments https://github.com/rails/rails/pull/18323
  77. 275.

    5JQ Wrap things in Objects, only test message has been

    invoked in controller skinny controller
  78. 276.

    describe "#create" do context "success" do it "sent welcome mail"

    do allow(UserMailer).to receive(:welcome) do_request expect(UserMailer).to have_received(:welcome) end end end &YBN QMF
  79. 277.

    describe "#create" do context "success" do it "sent welcome mail"

    do allow(Payment).to receive(:charge!) do_request expect(Payment).to have_received(:charge!) end end end
  80. 278.
  81. 281.

    describe User do context "associations" do; end context "validations" do;

    end describe ".class_method" do; end describe "#instance_method" do; end end $POWFOUJPO
  82. 285.

    describe User do subject { User.new } context "associations" do

    it { expect(subject).to have_many(:repos) } end end &YBN QMF Implicit subject
  83. 288.

    Post.trending scope :trending, -> { order("upvotes DESC") } describe Post

    do describe ".trending" do popular = create(:post, upvotes: 42) just_created = create(:post, upvotes: 1) trending_posts = Post.trending expect(trending_posts).to \ eq [popular, just_created] end end
  84. 292.

    require "rails_helper" describe EventsHelper do describe "#linkify_event" do it "works"

    do expect(linkify_event).to eq "RubyKaigi 11st-13rd Dec, 2015" end end end &YBN QMF
  85. 293.

    require "rails_helper" describe EventsHelper do describe "#linkify_event" do it "works"

    do expect(linkify_event).to eq "RubyKaigi 11st-13rd Dec, 2015" end end end EventsHelper::LinkifyEvent
  86. 294.

    require "rails_helper" describe EventsHelper do describe "#linkify_event" do it "works"

    do self expect(linkify_event).to eq "RubyKaigi 11st-13rd Dec, 2015" end end end RSpec::ExampleGroups:: EventsHelper::LinkifyEvent
  87. 295.

    require "rails_helper" describe EventsHelper do describe "#linkify_event" do it "works"

    do expect(linkify_event).to eq "RubyKaigi 11st-13rd Dec, 2015" end end end
  88. 301.

    # Either in spec/rails_helper.rb or # spec/email_helper.rb require "email_spec" RSpec.configure

    do |config| config.include EmailSpec::Helpers config.include EmailSpec::Matchers end $PO H
  89. 304.

    class UserMailer < ActionMailer::Base def welcome_user(user) @user = user mail(

    to: @user.email, subject: "Welcome to JollyGoodCode!" ) end end &YBN QMF
  90. 305.

    RSpec.describe UserMailer do describe "#welcome_user" do let(:user) { build_stubbed(:user) }

    let(:email) { email_for(user) } def email_for(user) UserMailer.welcome_user(user) end it { expect(email).to have_subject "Welcome to JollyGoodCode!" } it { expect(email).to deliver_to user.email } end end &YBN QMF
  91. 306.
  92. 312.
  93. 328.

    it "webmock example" do url = "https://api.github.com/users/juanitofatas" fixture = "spec/fixtures/github/juanitofatas.json"

    # stub_request(:get, url). to_return(body: File.read(fixture)) HTTP.get(url) expect(WebMock).to have_requested(:get, url) expect(a_request(:get, url)).to have_been_made end &YBN QMF
  94. 329.
  95. 330.

    it "webmock example" do url = "https://api.github.com/users/juanitofatas" fixture = "spec/fixtures/github/juanitofatas.json"

    stub_request(:get, url). to_return(body: File.read(fixture)) HTTP.get(url) expect(WebMock).to have_requested(:get, url) expect(a_request(:get, url)).to have_been_made end &YBN QMF
  96. 331.

    it "webmock example" do url = "https://api.github.com/users/juanitofatas" fixture = "spec/fixtures/github/juanitofatas.json"

    stub_request(:get, url). to_return(body: File.read(fixture)) HTTP.get(url) expect(WebMock).to have_requested(:get, url) expect(a_request(:get, url)).to have_been_made end &YBN QMF
  97. 332.

    it "webmock example" do url = "https://api.github.com/users/juanitofatas" fixture = "spec/fixtures/github/juanitofatas.json"

    stub_request(:get, url). to_return(body: File.read(fixture)) HTTP.get(url) expect(WebMock).to have_requested(:get, url) expect(a_request(:get, url)).to have_been_made end &YBN QMF
  98. 333.

    it "webmock example" do url = "https://api.github.com/users/juanitofatas" fixture = "spec/fixtures/github/juanitofatas.json"

    stub_request(:get, url). to_return(body: File.read(fixture)) HTTP.get(url) expect(WebMock).to have_requested(:get, url) expect(a_request(:get, url)).to have_been_made end &YBN QMF
  99. 334.

    it "webmock example" do url = "https://api.github.com/users/juanitofatas" fixture = "spec/fixtures/github/juanitofatas.json"

    stub_request(:get, url). to_return(body: File.read(fixture)) HTTP.get(url) expect(WebMock).to have_requested(:get, url) expect(a_request(:get, url)).to have_been_made end &YBN QMF https://github.com/sferik/t
  100. 336.
  101. 338.
  102. 339.

    Routing, Request, View Specs Page Object (Feature Spec) Front-end Testing

    Infrastructure Testing A/B Testing Smoke Testing (example)
  103. 340.

    Routing Specs Request Specs View Specs Page Object (Feature Spec)

    Front-end Testing Infrastructure Testing A/B Testing Smoke Testing (example) NOT COVERED
  104. 343.

    1. Write Feature Spec 2. New things with specs 3.

    Use Exception monitoring service
  105. 344.

    1. Write Feature Spec 2. New things with specs 3.

    Use Exception monitoring service 4. Find another job
  106. 350.

    I get paid for code that works, so my philosophy

    is to test as little as possible to reach a given level of confidence.— Kent Back “
  107. 362.
  108. 364.
  109. 365.
  110. 369.
  111. 370.
  112. 375.