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

Safe Testing in Ruby

sporto
September 26, 2013

Safe Testing in Ruby

A look at safe doubles, stubs and mock with Rspec and Bogus

sporto

September 26, 2013
Tweet

More Decks by sporto

Other Decks in Programming

Transcript

  1. let(:location) { Location.new } ... let(:user) { User.new(location: location, language:

    language) } We can create things manually Or use factories let(:user) { build(:user) } Thursday, 26 September 13
  2. it ‘increase the watch count’ { user.watch(video) expect(user.watch_count).to } Problem

    2: Too much happening class User def watch(video) ... video.watched_by(self) end end class Video def watched_by(user) ... end end Thursday, 26 September 13
  3. class User def watch(video) ... video.watched_by(self) end end Much faster!!

    No interaction with video anymore let(:video) { double.as_null_object } it { user.watch(video) expect(user.watch_count).to } Thursday, 26 September 13
  4. let(:video) { double.as_null_object } it { user.watch(video) expect(user.watch_count).to } But

    it may break class User def watch(video) ... video.watched_by(self) end end class Video def seen_by(user) ... end end Test still passes! Thursday, 26 September 13
  5. Integration breaks Fix the code in B Unit test for

    B breaks Fix unit test for B Change code in A Thursday, 26 September 13
  6. class User def watch(video) ... video.watched_by(self) end end Rspec doubles

    let(:video) { double.as_null_object } it { user.watch(video) ... 1 example, 0 failures still passes class Video def seen_by(user) ... end end Thursday, 26 September 13
  7. class User def watch(video) ... video.watched_by(self) end end undefined method

    `watched_by' it breaks Bogus Fakes class Video def seen_by(person) ... end end fake(:video) { Video } it { user.watch(video) ... Thursday, 26 September 13
  8. wrong number of arguments (2 for 1) it breaks Fakes

    (args) class User def watch(video) ... video.watched_by(self, args) end end class Video def watched_by(user) ... end end fake(:video) { Video } it { user.watch(video) ... Thursday, 26 September 13
  9. Rspec Stubbing let(:video) { double.as_null_object } before do video .stub(:time)

    .and_return(14.minutes) end it { user.watch(video) expect(user.busy_for).to eq(14.minutes) 1 example, 0 failures passes even if video.time doesn’t exist class User ... def busy_for current_video.time end ... end class Video def duration ... end Thursday, 26 September 13
  10. Bogus Stubbing fake(:video) { Video } before do stub(video) .time{

    14.minutes } end it { user.watch(video) expect(user.busy_for).to eq(14.minutes) } <Video:0x8051f2cc> does not respond to time This is what we want class User ... def busy_for current_video.time end ... end class Video def duration ... end Thursday, 26 September 13
  11. Stubbing (args) wrong number of arguments (0 for 1) fake(:video)

    { Video } before do stub(video) .time(any_args){ 14.minutes } end it { user.watch(video) expect(user.busy_for).to eq(14.minutes) } class User ... def busy_for current_video.time end ... end class Video def time(args) ... end Thursday, 26 September 13
  12. Rspec Mocking let(:video) { double.as_null_object } it { video.stub(:watched_by) user.watch(video)

    expect(video).to have_received(watched_by) } 1 example, 0 failures class User ... def watch(video) ... video.watched_by(self) end ... class Video def seen_by(person) ... end end Thursday, 26 September 13
  13. Bogus Mocks let(:video) { double.as_null_object } it { mock(video).watched_by(any_args) user.watch(video)

    } <Video:0x8051f2cc> does not respond to watched_by class User ... def watch(video) ... video.watched_by(self) end ... class Video def seen_by(person) ... end end Thursday, 26 September 13