Upgrade to Pro — share decks privately, control downloads, hide ads and more …

RSpec for Practical Rubyist

Sponsored · Your Podcast. Everywhere. Effortlessly. Share. Educate. Inspire. Entertain. You do you. We'll handle the rest. →

RSpec for Practical Rubyist

@ RubyConfTaiwan 2015

Avatar for Juanito Fatas

Juanito Fatas

September 11, 2015

More Decks by Juanito Fatas

Other Decks in How-to & DIY

Transcript

  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. rubytaiwan/taipei Things to know about Taipei put together by Ruby

    Taiwan Community Inspired from RubySG/Singapore
  3. %

  4. ∴

  5. RSPEC FOR THE PRACTICAL RUBYIST EXPLAINING SIMPLY AND QUICKLY ALL

    THE ELEMENTS OF CONTROLLER, MODEL, VIEW, HELPER, INTEGRATION, FEATURE WITHout ANSWERS TO PROBLEMS
  6. 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 ✨
  7. 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
  8. class Something < Minitest::Test def test_works assert_equal 11, 10 end

    def test_really_works assert_equal 11, 11 end end (Unit)Test
  9. 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)
  10. 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)
  11. 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
  12. describe it expect to a series of tests is a

    test an actual object match something
  13. 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*
  14. 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
  15. 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
  16. describe Baz let(:foo) { "bar" } it "…" do ...

    end end foo will be available in it blocks under the same scope!
  17. let(:foo) { sleep 42 } it "…" do ... end

    Finished in 0.04424 seconds it "…" do ... end
  18. let(:foo) { sleep 42 } it "…" do foo end

    Finished in 42.03924 seconds it "…" do ... end
  19. let!(:foo) { sleep 42 } it "…" do ... end

    Finished in 42.03924 seconds it "…" do ... end
  20. 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
  21. 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
  22. 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
  23. 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
  24. 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
  25. 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
  26. setup exercise verify teardown everything we need the real work

    our expectations back to original state
  27. before { user = User.new(password: "passw0rd") } it "should encrypt

    password" do user.save expect(user.encrypted_password).not_to eq nil end Put together
  28. it "should encrypt password" do user = User.new(password: "passw0rd") user.save

    expect(user.encrypted_password).not_to eq nil end Strategy Spaces
  29. Spy

  30. Fixture # spec/fixtures/users.yml juanitofatas: name: JuanitoFatas email: [email protected] # 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:"…">
  31. 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
  32. Test like how user use it Use real database records

    Don’t mock or stub objects External Service can stub 5JQ
  33. &YBN QMF feature "Auth" do given { ... } background

    { ... } scenario "show name" do ... end end
  34. RSpec.feature "…" do end Capybara API will be available in

    here http://www.rubydoc.info/github/jnicklas/capybara/master#The_DSL
  35. "1* page visit current_path click_on find fill_in choose check select

    attach_file https://github.com/jnicklas/capybara#the-dsl
  36. &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
  37. &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
  38. &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
  39. require "rails_helper" RSpec.describe ShopsController do describe "#index" do ... end

    describe "#new" do ... end describe "#create" do ... end … $POWFOUJPO
  40. describe "#show" do ... end describe "#edit" do ... end

    describe "#update" do ... end describe "#destroy" do ... end end $POWFOUJPO
  41. 5JQ Ordering should be the same as your actions in

    controller index new create show edit update destroy
  42. params request response session flash cookie "1* get post patch

    put head delete ActionController::TestCase
  43. 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
  44. 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
  45. describe "#index" do def do_request get :index end before {

    do_request } it { expect(response).to be_success } end JOEFY
  46. describe "#new" do def do_request get :new end before {

    do_request } it { expect(response).to be_success } end OFX
  47. describe "#create" do def do_request post :create, thing: params end

    context "success" do ... end context "failure" do ... end end DSFBUF
  48. 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
  49. 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
  50. 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
  51. 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
  52. 3BJMT post :show, { id: 1 }, { user_id: 1

    }, { notice: "flash message" }
  53. 3BJMT post :show, { id: 1 }, {}, { notice:

    "flash message" } params session flash
  54. 3BJMT post :show, { shop_id: 1 }, {}, { notice:

    "flash message" } params session flash
  55. 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
  56. 5JQ Wrap things in Objects, only test message has been

    invoked in controller skinny controller
  57. 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
  58. 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
  59. describe User do context "associations" do; end context "validations" do;

    end describe ".class_method" do; end describe "#instance_method" do; end end $POWFOUJPO
  60. describe User do subject { User.new } context "associations" do

    it { expect(subject).to have_many(:repos) } end end &YBN QMF Implicit subject
  61. 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
  62. 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
  63. 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
  64. 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
  65. 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
  66. # 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
  67. class UserMailer < ActionMailer::Base def welcome_user(user) @user = user mail(

    to: @user.email, subject: "Welcome to JollyGoodCode!" ) end end &YBN QMF
  68. 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
  69. 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
  70. 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
  71. 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
  72. 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
  73. 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
  74. 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
  75. Routing, Request, View Specs Page Object (Feature Spec) Front-end Testing

    Infrastructure Testing A/B Testing Smoke Testing (example)
  76. Routing Specs Request Specs View Specs Page Object (Feature Spec)

    Front-end Testing Infrastructure Testing A/B Testing Smoke Testing (example) NOT COVERED
  77. 1. Write Feature Spec 2. New things with specs 3.

    Use Exception monitoring service
  78. 1. Write Feature Spec 2. New things with specs 3.

    Use Exception monitoring service 4. Find another job
  79. 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 “