RSpec for Practical Rubyist

RSpec for Practical Rubyist

@ RubyConfTaiwan 2015

771951f55ed37335f238e1a80dfda9cd?s=128

Juanito Fatas

September 11, 2015
Tweet

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. 2015!!! RubyConFTW

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

    Taiwan Community Inspired from RubySG/Singapore
  4. Juanito Fatas !

  5. juanitofatas/fast-ruby Collection of Idioms, Benchmarks, etc. for Faster Ruby Code

    Inspired by @sferik and Ruby Community
  6. Employee #1

  7. The Birth of deppbot

  8. JuanitoFatas/rubygems.org/pull/1

  9. None
  10. None
  11. None
  12. JOIN OPEN SOURCE

  13. Tweet at Me @juanitofatas " #rubyconFTW #rubyconFTW2015

  14. None
  15. Introducing 4K Live Photos iPhone 6S Plus

  16. muan/mojibar

  17. Emoji is Awesome!

  18. 95% of time preparations of this talk

  19. Tweak fonts and think about emojis

  20. First of all

  21. It’s been a tough day

  22. %

  23. None
  24. Some mathematics

  25. My first talk ever, 5-minute long ⏳

  26. My second talk, 50-minute long

  27. Let ψ = 5

  28. Let ω = 50

  29. ω — ψ =

  30. 50 — ψ =

  31. 50 — 5 =

  32. 50 — 5 =10

  33. I am a 10x Speaker

  34. Q.E.D.

  35. Matz is Great! ,,,,,,

  36. Talk Title Origin

  37. Richard Feynman

  38. None
  39. RSPEC FOR THE PRACTICAL RUBYIST EXPLAINING SIMPLY AND QUICKLY ALL

    THE ELEMENTS OF CONTROLLER, MODEL, VIEW, HELPER, INTEGRATION, FEATURE WITHout ANSWERS TO PROBLEMS
  40. Why This Talk

  41. Rubyists in Taiwan are courageous.

  42. None
  43. Raise the awareness of Testing in Thiland

  44. Journey into Rails Testing ⛵0

  45. Introductory Talk No theory, and TDD because How-to, but not

    what & why Tutorial type
  46. Just Enough Background

  47. 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 ✨
  48. The Rabbit Hole

  49. What is RSpec "

  50. None
  51. https://relishapp.com/rspec RSpec Core | RSpec Expectations | RSpec Mocks |

    RSpec Rails
  52. RSpec Minitest vs

  53. 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
  54. class Something < Minitest::Test def test_works assert_equal 11, 10 end

    def test_really_works assert_equal 11, 11 end end (Unit)Test
  55. Test cases are Class Minitest::Test Tests are methods inside test

    case
  56. 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)
  57. 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)
  58. None
  59. RSpec RAILS

  60. A Gentle Introduction to RSpec

  61. rspec rspec-core rspec-expectations rspec-mocks MetaRubyGem

  62. How to run

  63. . means Passed F means Failure E means Error *

    means Pending S means Skip
  64. Sample Output

  65. None
  66. $ rspec --init

  67. .rspec --color --require spec_helper https://relishapp.com/rspec/rspec-core/v/3-3/docs/command-line/

  68. spec/ spec_helper.rb

  69. Magic Spells

  70. 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
  71. describe it expect to

  72. describe it expect to a series of tests

  73. describe it expect to a series of tests is a

    test
  74. describe it expect to a series of tests is a

    test an actual object
  75. describe it expect to a series of tests is a

    test an actual object match something
  76. describe how methods works, group of test examples, series of

    behaviour
  77. describe User do ... end

  78. RSpec.describe describe config.disable_monkey_patching! in spec_helper.rb 34QFD

  79. RSpec.describe User do describe ".authenticate" do ... end describe "#name"

    do ... end end describe can be nested
  80. RSpec.describe User do describe ".authenticate" do ... end describe "#name"

    do ... end end
  81. RSpec.describe User do describe ".authenticate" do ... end describe "#name"

    do ... end end
  82. RSpec.describe User do describe ".authenticate" do ... end describe "#name"

    do ... end end
  83. RSpec.describe User do describe ".authenticate" do ... end describe "#name"

    do ... end end
  84. RSpec.describe User do describe ".authenticate" do ... end describe "#name"

    do ... end end
  85. context scenarios in your implementation same as describe

  86. context "when…" do ... end context "with…" do end

  87. it a single test example inside of describe / context

    block
  88. it "eats something" do ... end

  89. describe SteveJobs do context "with stylus" do it "yucks" do

    end end end
  90. $ bin/rspec spec/models/steve_jobs_spec.rb --format doc SteveJobs with stylus yucks

  91. it "hello" do … end 4JOHMF-JOF .VMUJ-JOF it { …

    }
  92. example "" do ... end "WPJE specify "" do ...

    end
  93. before things to do before test run

  94. before { ... } it "" do ... end

  95. before do ... end it "" do ... end

  96. after things to do after test run

  97. it "" do ... end after { ... }

  98. it "" do ... end after do … end

  99. inside of it

  100. Expectations & matchers come in

  101. expect(actual) expect something

  102. to eq(expected) to equal what we expected

  103. it "…" do expect(1+1).to eq(2) end from rspec-expectations

  104. it "…" do expect(1+1).to eq(2) end matcher

  105. expect(1+1).to eq(2)

  106. 1+1 is 2? Let’s prove

  107. 162 pages to prove 1+1=2

  108. it "…" do expect(1+1).to eq(2) end Example instance http://git.io/vZfvX

  109. it "…" do self.expect(1+1).to self.eq(2) end Example Example

  110. it "…" do self.expect(1+1).to self.eq(2) end instance of ExpectationTarget http://git.io/vZffB

  111. ET = ExpectationTarget class Example def self.expect(actual) ET.new(actual) end end

  112. ET = ExpectationTarget class Example def self.expect(actual) ET.new(actual) end end

  113. ET = ExpectationTarget class Example def self.expect(actual) ET.new(actual) end end

  114. class ET attr_reader :actual def initialize(actual) @actual = actual end

    end
  115. it "…" do self.expect(1+1).to self.eq(2) end Example

  116. it "…" do self.expect(1+1).to self.eq(2) end Matcher

  117. class Example def self.eq(expected) EqMatcher.new(expected) end end EqMatcher is actually

    BuiltIn::Eq http://git.io/vZffi
  118. class EqMatcher def initialize(expected) @expected = expected end def matches

    ... end end
  119. it "…" do self.expect(1+1).to self.eq(2) end instance of ExpectationTarget

  120. it "…" do self.expect(1+1).to self.eq(2) end ExpectationTarget#to

  121. class ExpectationTarget def to(matcher) Postive.handle_matcher(actual, matcher) end end

  122. class ExpectationTarget def to(matcher) Postive.handle_matcher(actual, matcher) end end Postive is

    actually PositiveExpectationHandler http://git.io/vZfJK
  123. class Positive def self.handle_matcher(actual, matcher) matcher.matches(actual) end end http://git.io/vZqoX

  124. class Positive def self.handle_matcher(actual, matcher) matcher.matches(actual) end end

  125. class EqMatcher def matches(actual) match(expected, actual) end private def match(expected,

    actual) actual == expected end end
  126. class EqMatcher def matches(actual) match(expected, actual) end private def match(expected,

    actual) actual == expected end end
  127. class EqMatcher def matches(actual) match(expected, actual) end private def match(expected,

    actual) actual == expected end end http://git.io/vZfUp
  128. voilà, old sport!

  129. it "…" do expect(user.admin?).to be_true end `be` matcher be_true be_false

    be_truthy be_falsy be_nil be
  130. 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*
  131. 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
  132. 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
  133. RSpec predicate expect(user.admin?).to be_true expect(user).to be_admin

  134. Read in English Most of the time There is a

    matcher for it ( VJEF
  135. Stick with eq as a Starting Point ( VJEF KISS

  136. expect(user.admin?).to be_true expect(user.admin?).to eq true

  137. RSpec built-in matchers have better error messages ( VJEF

  138. let lazily-evaluated block to shared object between tests

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

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

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

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

    Finished in 42.03924 seconds it "…" do ... end
  143. Prefer let over @instance_var ( VJEF

  144. RSpec Mocks

  145. RSpec Mocks To mock a mocking bird

  146. We are dealing with objects and objects

  147. collaborators of each other

  148. Sometimes it costs a lot to setup collaborators

  149. TDD Tired-Driven Development

  150. Move Fast and Break Things drive slow but stay safe

  151. Double

  152. None
  153. A fake object for real object

  154. RSpec::Mocks:: ExampleMethods #double http://git.io/vZq6F "1*

  155. user = double("User")

  156. Faking message and its return value

  157. RSpec::Mocks:: ExampleMethods #allow http://git.io/vZq6F "1*

  158. allow(obj).to receive(:msg).and_return(value)

  159. user = double("User") allow(user).to receive(:admin?). and_return(true) allow(user).to receive(:admin?) { true

    }
  160. user = double("User") allow(user).to receive(:admin?). and_return(true) allow(user).to receive(:admin?) { true

    }
  161. user = double("User") allow(user).to receive(:admin?). and_return(true) allow(user).to receive(:admin?) { true

    }
  162. user.admin? => true

  163. user = double("User", admin?: true)

  164. Stub & Mock

  165. 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
  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 Stub
  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 Mock
  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 Failure/Error: expect(User).to receive(:new) Mock
  169. Mock will verify While Stub not

  170. 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
  171. 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
  172. Phases of Testing

  173. setup exercise verify teardown everything we need the real work

    our expectations back to original state
  174. Encrypt user password in database &YBN QMF

  175. setup user = User.new(password: "passw0rd")

  176. user.save exercise

  177. expect(user.encrypted_password).to be_present verify

  178. RSpec’ve got us covered teardown

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

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

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

  182. Like 007, can do anything

  183. Can respond to any messages

  184. oo7 = spy oo7.can_jump? oo7.can_drive_car? oo7.can_play_poker? oo7.can_write_ruby?

  185. spy is the Null Object of double spy = double.as_null_object

  186. oo7 = spy oo7.hungry? expect(oo7).to have_received(:hungry?)

  187. oo7 = spy oo7.tired? expect(oo7).to have_received(:tired?) Just like Stub!

  188. RSpec 2 v.s RSpec 3 make stub and mock is

    confusing
  189. But you can just try and explore their difference

  190. That’s enough to write many tests!

  191. RSpec & Rails

  192. gem "rspec-rails" bundle rails generate rspec:install *OTUBMM in development and

    test group
  193. spec/ rails_helper.rb Only when you need Rails

  194. Try not to load rails_helper whenever possible 5JQ

  195. config.infer_spec_type_from_file_location! # spec/models/user_spec.rb RSpec.describe User, type: :model do # automatically

    mixin functionalities end Infer type of test automatically
  196. Metadata

  197. RSpec.describe User, type: :model do end metadata

  198. According to type of tests, RSpec will mixin different functionality

    automagically
  199. RSpec.describe User, focus: true do end metadata $ rspec --tag

    focus only run spec with special tag
  200. Rails & Testing

  201. RAILS_ENV = test config/environments/test.rb

  202. bin/rake db:test:prepare run pending migrations and load schema https://github.com/rails/rails/blob/v4.2.4/activerecord/lib/active_record/railties/databases.rake#L359-L364

  203. ActiveSupport::TestCase ActionController::TestCase ActionMailer::TestCase ActionView::TestCase ActiveJob::TestCase ActionDispatch::IntegrationTest Read these API docs

    on http://api.rubyonrails.org/
  204. Fixture

  205. 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:"…">
  206. FactoryGirl A DSL to generate objects

  207. # spec/factories/user.rb Factory.define do factory :user do name "Juanito Fatas"

    email "juanito@jollygoodcode.com" end end
  208. FactoryGirl.attributes_for(:user) # => { name: "JuanitoFatas", email: "juanito@jollygoodcode.com" }

  209. # In spec FactoryGirl.create(:user) FactoryGirl.build(:user) # Map to Active Record

    User.create(…) User.new(…)
  210. gem "factory_girl_rails" bundle mkdir spec/factories *OTUBMM in development and test

    group
  211. spec/factories/*.rb $POWFOUJPO * is respective model name, user.rb

  212. 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
  213. Minimum Valid Object 5JQ

  214. Types of Test

  215. https://robots.thoughtbot.com/rails-test-types-and-the-testing-pyramid

  216. https://robots.thoughtbot.com/rails-test-types-and-the-testing-pyramid Bottom Top

  217. https://robots.thoughtbot.com/rails-test-types-and-the-testing-pyramid Inside Outside

  218. https://robots.thoughtbot.com/rails-test-types-and-the-testing-pyramid User Code

  219. https://robots.thoughtbot.com/rails-test-types-and-the-testing-pyramid Coverage

  220. https://robots.thoughtbot.com/rails-test-types-and-the-testing-pyramid Fast Slow

  221. None
  222. Feature Spec Outside-in, Acceptance / Customer Test, End-to-End, Top down

  223. require "rails_helper" spec/features/*_spec.rb $POWFOUJPO

  224. ( PBM Automate the manual repeated process Browser, check, refresh,

    repeat
  225. Test like how user use it Use real database records

    Don’t mock or stub objects External Service can stub 5JQ
  226. Happy Path for a given feature 5JQ

  227. API to interact with Browser ( FN T capybara Version

    2.4.0+ is recommended
  228. group :development, :test do gem "capybara" end bundle install *OTUBMM

  229. require "capybara/rails" # in spec/rails_helper.rb $PO H

  230. database_rewinder ( FN T Ensure clean state across tests

  231. group :test do gem "database_rewinder" end *OTUBMM

  232. RSpec.configure do |config| config.before :suite do DatabaseRewinder.clean_all end config.after :each

    do DatabaseRewinder.clean end end $PO H
  233. background feature scenario given "1*

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

    { ... } scenario "show name" do ... end end
  235. background feature scenario given before describe it let http://git.io/vGyaV alias

    alias alias alias "1*
  236. RSpec.feature "…" do end Capybara API will be available in

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

    attach_file https://github.com/jnicklas/capybara#the-dsl
  238. 3BDL5FTU Fastest No JavaScript Can access within Rack No Server

    Required
  239. &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
  240. &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
  241. &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
  242. Drivers

  243. % SJWFST Plain Firefox Webkit PhantomJS Rack-Test Selenium Capybara-webkit Poltergeist

    Single DSL to rule them all
  244. RSpec.describe User, js: true do ... end enable javascript_driver #SPX

    TFS
  245. 4FMFOJVN Selenium 2.0 Firefox JavaScript Can access Remote API EFGBVMU

  246. $BQZCBSB8FCLJU Headless Testing JavaScript Faster than selenium

  247. 1PMUFSHFJTU Headless Testing JavaScript Can Find JS Error No render

    engine needed
  248. Capybara.default_driver Capybara.javascript_driver $PO H

  249. Controller Spec Functional Test

  250. require "rails_helper" spec/controllers/*_spec.rb describe "#action" $POWFOUJPO * is respective controller

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

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

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

    controller index new create show edit update destroy
  254. response correct & success redirected right authentications session, flash, cookie

    render correct template instance variable ( PBM
  255. params request response session flash cookie "1* get post patch

    put head delete ActionController::TestCase
  256. expect(response).to render_template(:index) expect(response).to redirect_to(location) expect(response.status).to eq(200) expect(flash[:alert]).to eq I18n.t("failed") "1*

  257. Can wrap request in method — abstractions 5JQ def do_request

    get :show, params end
  258. 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
  259. 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
  260. RESTful controller spec

  261. RSpec.describe ThingsController do end TLFMUPO

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

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

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

    context "success" do ... end context "failure" do ... end end DSFBUF
  265. 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
  266. 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
  267. 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
  268. 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
  269. 5JQ Try to keep the specs shape the same across

    controllers
  270. 3BJMT post :show, { id: 1 }, { user_id: 1

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

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

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

    invoked in controller skinny controller
  275. 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
  276. 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
  277. Model Spec

  278. Test how you tried in rails console ( PBM

  279. require "rails_helper" spec/models/*_spec.rb $POWFOUJPO

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

    end describe ".class_method" do; end describe "#instance_method" do; end end $POWFOUJPO
  281. Use shoulda to write one-liner spec for associations and validations

    5JQ
  282. ActiveSupport::TestCase 3BJMT

  283. describe User do context "associations" do it { expect(User.new).to have_many(:repos)

    } end end "TTPDJBUJPO
  284. describe User do subject { User.new } context "associations" do

    it { expect(subject).to have_many(:repos) } end end &YBN QMF Implicit subject
  285. describe User do context "associations" do it { is_expected.to have_many(:repos)

    } end end &YBN QMF
  286. describe User do context "associations" do it { is_expected.to validate_presence_of

    :name } end end 7BMJEBUJPO
  287. 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
  288. Helper Spec

  289. ( PBM Test the view helper as you expected

  290. require "rails_helper" spec/helpers/*_spec.rb $POWFOUJPO

  291. 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
  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 EventsHelper::LinkifyEvent
  293. 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
  294. 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
  295. Mailer Spec

  296. ActionMailer::TestCase ActionMailer::Base.deliveries ActionMailer::MessageDelivery 3BJMT

  297. spec/mailers/*_spec.rb $POWFOUJPO

  298. email_spec ( FN T Why this not in RSpec?

  299. group :test do gem "email_spec" end *OTUBMM

  300. # 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
  301. reply_to deliver_to deliver_from bcc_to cc_to "1* have_subject have_body_text have_header

  302. Sent successfully Sent at correct time Sent to right person

    Email content ( PBM
  303. class UserMailer < ActionMailer::Base def welcome_user(user) @user = user mail(

    to: @user.email, subject: "Welcome to JollyGoodCode!" ) end end &YBN QMF
  304. 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
  305. Job Spec

  306. Job invokes correct methods ( PBM

  307. ActiveJob::TestCase ActiveJob::TestHelper 3BJMT

  308. spec/jobs/*_spec.rb $POWFOUJPO

  309. it "sync repos" do allow(RepoSync).to receive(:new) RepoSyncJob.perform_now(repo) expect(RepoSync).to have_received(:new) end

    &YBN QMF Sending right messages
  310. it "sync repos" do allow(RepoSync).to receive(:new) RepoSyncJob.perform_now(repo) expect(RepoSync).to have_received(:new) end

    &YBN QMF Logic should be already tested in RepoSync specs
  311. View Spec

  312. Request Spec

  313. Plain Old Ruby Object

  314. Similar to Model Spec without loading Rails

  315. Interact with the world

  316. Run without network Avoid connectivity issues ( PBM

  317. API limit Slower Test relies on internet Service no sandbox

    mode Service not exist 8 IZ
  318. spec/**/*_spec.rb '3 &&% 0 . lib/github_client.rb spec/lib/github_client_spec.rb

  319. webmock ( FN T Making real request IS A CRIME

  320. group :test do gem "webmock" end *OTUBMM

  321. require "webmock/rspec" WebMock.disable_net_connect! (allow_localhost: true) $PO H

  322. stub_request( HTTP verb, path ).with( HEADER HASH ).to_return( RESPONSE HASH

    ) 4UVCCJOH
  323. expect(WebMock).to have_requested(…). with(…) 4FUUJOH&YQFDUBUJPOT

  324. expect( a_request(…) ).to have_been_made 4FUUJOH&YQFDUBUJPOT

  325. VCR ( FN T Record response from real API or

    service cassettes
  326. $ curl File.read Ruby Objects Faking responses

  327. 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
  328. &YBN QMF

  329. 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
  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
  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
  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
  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 https://github.com/sferik/t
  334. &YBN QMF many stub_request examples sferik/t

  335. Debugging

  336. stop spring pry-rails + binding.pry byebug everywhere p + puts

    + pp + raise
  337. Closing

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

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

    Front-end Testing Infrastructure Testing A/B Testing Smoke Testing (example) NOT COVERED
  340. LEGACY CODE

  341. Skip Pending v.s. not run at all run but won’t

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

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

    Use Exception monitoring service 4. Find another job
  344. DON’T TEST private Method test the method which uses it

  345. Wrap Everything in objects so much easier to test

  346. Use shoulda to simplify when you get tired.

  347. Use tools to simplify when you get tired.

  348. Don’t aim for 100% test coverage

  349. 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 “
  350. We read more than we write

  351. Anything that can go wrong, will go wrong

  352. That’s why we write tests

  353. Tests are also code. Will become stinky, break up when

    it’s time
  354. There are million ways of how things are tested

  355. There’s no tomorrow.

  356. WRITE TEST NOW

  357. A test is better than no test

  358. Feature Model Controller

  359. Do Code Review

  360. Team Style Guide

  361. Takeaways

  362. ALWAYS BE TESTING

  363. Resource

  364. Talks

  365. https://www.youtube.com/watch?v=MA4jJNUG_dI

  366. http://git.io/vsOKE

  367. https://www.youtube.com/watch?v=Libc0-0TRg4

  368. Books

  369. None
  370. https://leanpub.com/rspecbook RUBYCONFTW2015 ⯜顤 8 PSL*O1SPHSFTT IPROMISEYOUIWILLWRITETESTS ! ✿䫓 ! 45RGE⑆桡⻇㔑

    D[,WCPKVQ(CVCU
  371. Talk to me! I’m happy to help you

  372. 6JCPM[QW HQT.KUVGPKPI

  373. 6GC6KOG ☕

  374. None