MyQuinceLife.com - Dinastia Aguilar. Double trouble: Cover Girl tie
Double Trouble
-
Upload
gsterndale -
Category
Technology
-
view
1.315 -
download
5
description
Transcript of Double Trouble
DOUBLE TROUBLEClarity on test doubles.
TESTING PHASES
exercise
verify
teardown
let(:sox) { Team.new “Boston” }let(:drays) { Team.new “Tampa” }before { sox.play(drays) }
it “should set standings” do expect(drays).to be_losingend
after { standings.delete_all }
setup
TESTING PHASES
setup
exercise
verify
teardown
→let(:sox) { Team.new “Boston” }let(:drays) { Team.new “Tampa” }before { sox.play(drays) }
it “should set standings” do expect(drays).to be_losingend
after { standings.delete_all }
TESTING PHASES
excercise
setup
verify
teardown
→
let(:sox) { Team.new “Boston” }let(:drays) { Team.new “Tampa” }before { sox.play(drays) }
it “should set standings” do expect(drays).to be_losingend
after { standings.delete_all }
TESTING PHASES
verify
setup
exercise
teardown→
let(:sox) { Team.new “Boston” }let(:drays) { Team.new “Tampa” }before { sox.play(drays) }
it “should set standings” do expect(drays).to be_losingend
after { standings.delete_all }
TESTING PHASES
teardown
setup
exercise
verify
→
let(:sox) { Team.new “Boston” }let(:drays) { Team.new “Tampa” }before { sox.play(drays) }
it “should set standings” do expect(drays).to be_losingend
after { standings.delete_all }
WHAT IS A TEST DOUBLE?
WHAT IS A TEST DOUBLE?
SUT
DOC
WHAT IS A TEST DOUBLE?
SUT
DOC
WHAT IS A TEST DOUBLE?
SUT
Indirect Output
DOC
WHAT IS A TEST DOUBLE?
SUT
Indirect Output
Indirect Input
DOCTestDouble
WHAT IS A TEST DOUBLE?
SUT
Indirect Output
Indirect Input
TEST DOUBLE PATTERNS
•Dummy Object
• Fake Object
•Mock Object
• Test Stub
• Test Spy
DUMMY OBJECT
A placeholder that is passed to the SUT and never used
let(:side_a) { 1 }let(:side_b) { 2 }let(:dummy) { Object.new }
subject { HighSchoolTrig.hypotenuse(a, b, dummy) }
it { should eq 2.236 }
FAKE OBJECT
An object which replaces the real DOC with an alternate implementation of the same functionalityclass FakePiCalcdef pi; 3.14159; end
end
let(:radius) { 2 }
before { MyGeo.pi_calculator = FakePiCalc }
subject { MyGeo.circumference(radius) }
it { should eq 13 }
MOCKS, STUBS & SPIES
An example:
class User < ActiveRecord::Base
before_create :enqueue_welcome_message
def enqueue_welcome_message queue = Application.config.email_queue raise(“Failed to queue”) unless queue.push(email, “Welcome”) end
end
NO DOUBLES
let(:email) { “[email protected]” }
subject { User.create(email: email) }
it { should be_persisted }its(:username) { should eq email }
MOCK OBJECTAn object which replaces the real DOC that can verify indirect output from the SUT with expectationslet(:mock_queue) { double() }let(:email) { “[email protected]” }
before do Application.config.email_queue = mock_queueexpect(mock_queue).to receive(:push).with(email, “Welcome”)
endsubject { User.create(email: email) }
it { should be_persisted }its(:username) { should eq email }
TEST STUBAn object which replaces the real DOC to control indirect input to the SUTlet(:stub_queue) { double(push: true) }let(:email) { “[email protected]” }
before do Application.config.email_queue = stub_queueend
subject { User.create(email: email) }
it { should be_persisted }its(:username) { should eq email }
TEST SPYA more capable Test Stub allowing verification of indirect output from the SUTlet(:spy_queue) { double(push: true) }let(:email) { “[email protected]” }
before do Application.config.email_queue = spy_queueend
subject { User.create(email: email) }
it { should be_persisted }its(:username) { should eq email }it “should enqueue welcome message” do expect(spy_queue).to have_received(:push).with(email, “Ohai”)end
DESIGNING FOR DOUBLES
•Dependency Lookup
•Dependency Injection
class Buddy def good_friend?; on_tap.craft?; end
def on_tapFridge.cold_one
endend
describe Buddy, “serving coors” do # TODO control indirect input to the SUT it “should not be a good friend” do expect(subject).not_to be_good_friend end
DEPENDENCY LOOKUPclass Buddy def good_friend?; on_tap.craft?; end
def on_tapFridge.cold_one
endend
describe Buddy, “serving coors” do let(:coors) { double(craft?: false) }
before { Fridge.stubs(:cold_one) { coors } } it “should not be a good friend” do expect(subject).not_to be_good_friend end
class Buddyattr_accessor :fridge def good_friend?; on_tap.craft?; end
def [email protected]_one
endend
describe Buddy, “serving coors” do let(:coors) { double(craft?: false) } let(:stub_fridge) { double(cold_one: coors) } before { subject.fridge = stub_fridge } it “should not be a good friend” do expect(subject).not_to be_good_friend end
DEPENDENCY INJECTION
RETROFITTING
• Test-Specific Subclasses
• Test Hooks
class Buddy
attr_reader :supermarket
def make_breakfast(request=“Steak & eggs”)ingredients = supermarket.find(request)prepare(ingredients)
endend
TEST-SPECIFIC SUBCLASSESclass Buddy
attr_reader :supermarket
def make_breakfast(request=“Steak & eggs”)ingredients = supermarket.find(request)prepare(ingredients)
endend
class TestBuddy < Buddyattr_writer :supermarket
end
TEST HOOKSclass Buddyif ENV != “TEST”attr_reader :supermarket
elseattr_accessor :supermarket
end
def make_breakfast(request=“Steak & eggs”)ingredients = supermarket.find(request)prepare(ingredients)
endend
ARE THEY FOR YOU?
“MOCKIST” TDD / BDD
• Uses mocks for all DOCs
• Likes the test writing process to inform design decisions
• Tests in strict isolation
CLASSIC TDD
• Uses test doubles only for awkward DOCs, favoring “real” objects
•Minimizes coupling between tests and implementation
• Tests small clusters of components, not isolated units
CLASSIC TDDERS CONSIDER USING A TEST DOUBLE IF:
• The behavior of the DOC cannot be changed/observed
• Use of the DOC could cause unwanted side-effects
• The DOC is too slow
• The DOC doesn’t exist yet
OVERUSE CAN LEAD TO:
•Over specified tests of the SUT’s process, not its result
• Fragile tests that break when implementation changes
• Untested integration
• Less time on Hacker News while your build runs
MORE
xUnit Test Patterns: xunitpatterns.com
Mocks aren’t Stubs by Martin Fowler: martinfowler.com/articles/mocksArentStubs.html
A case against a case against mocking and stubbing by David Chelimsky: blog.davidchelimsky.net/2008/12/11/a-case-against-a-case-against-mocking-and-stubbing/
Timecop for testing time-dependent code: github.com/travisjeffery/timecop
RSpec: rspec.info
MiniTest: ruby-doc.org/stdlib
Mocha: github.com/freerange/mocha