126
Don’t Mock Yourself Out David Chelimsky Articulated Man, Inc

David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

  • Upload
    others

  • View
    2

  • Download
    0

Embed Size (px)

Citation preview

Page 1: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

Don’t MockYourself Out

David ChelimskyArticulated Man, Inc

Page 2: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls
Page 4: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

Classical and Mockist Testing

Page 5: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

Classical and Mockist Testing

Page 6: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

Classical and Mockist Testing

Page 7: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

classicist mockist

Page 8: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

merbist railsist

Page 9: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

rspecist testunitist

Page 10: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls
Page 11: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

ist bin einred herring

Page 12: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

The big issue here is when to use a

mock

http://martinfowler.com/articles/mocksArentStubs.html

Page 13: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

agenda๏ overview of stubs and mocks

๏ mocks/stubs applied to rails

๏ guidelines and pitfalls

๏ questions

Page 14: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

test double

Page 15: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

test stubdescribe Statement do it "uses the customer name in the header" do customer = stub("customer") customer.stub(:name).and_return('Joe Customer') statement = Statement.new(customer)

statement.header.should == "Statement for Joe Customer" endend

Page 16: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

test stubdescribe Statement do it "uses the customer name in the header" do customer = stub("customer") customer.stub(:name).and_return('Joe Customer') statement = Statement.new(customer)

statement.header.should == "Statement for Joe Customer" endend

Page 17: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

test stubdescribe Statement do it "uses the customer name in the header" do customer = stub("customer") customer.stub(:name).and_return('Joe Customer') statement = Statement.new(customer)

statement.header.should == "Statement for Joe Customer" endend

Page 18: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

test stubdescribe Statement do it "uses the customer name in the header" do customer = stub("customer") customer.stub(:name).and_return('Joe Customer') statement = Statement.new(customer)

statement.header.should == "Statement for Joe Customer" endend

Page 19: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

mock objectdescribe Statement do it "logs a message when printed" do customer = stub("customer") customer.stub(:name).and_return('Joe Customer') logger = mock("logger") statement = Statement.new(customer, logger)

logger.should_receive(:log).with(/Joe Customer/) statement.print endend

Page 20: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

mock objectdescribe Statement do it "logs a message when printed" do customer = stub("customer") customer.stub(:name).and_return('Joe Customer') logger = mock("logger") statement = Statement.new(customer, logger)

logger.should_receive(:log).with(/Joe Customer/) statement.print endend

Page 21: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

mock objectdescribe Statement do it "logs a message when printed" do customer = stub("customer") customer.stub(:name).and_return('Joe Customer') logger = mock("logger") statement = Statement.new(customer, logger)

logger.should_receive(:log).with(/Joe Customer/) statement.print endend

Page 22: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

mock objectdescribe Statement do it "logs a message when printed" do customer = stub("customer") customer.stub(:name).and_return('Joe Customer') logger = mock("logger") statement = Statement.new(customer, logger)

logger.should_receive(:log).with(/Joe Customer/) statement.print endend

Page 23: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

mock objectdescribe Statement do it "logs a message when printed" do customer = stub("customer") customer.stub(:name).and_return('Joe Customer') logger = mock("logger") statement = Statement.new(customer, logger)

logger.should_receive(:log).with(/Joe Customer/) statement.print endend

Page 24: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

method level concepts

Page 25: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

describe Statement do it "logs a message when printed" do customer = Object.new logger = Object.new customer.stub(:name).and_return('Joe Customer') statement = Statement.new(customer, logger)

logger.should_receive(:log).with(/Joe Customer/) statement.print endend

Page 26: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

describe Statement do it "logs a message when printed" do customer = Object.new logger = Object.new customer.stub(:name).and_return('Joe Customer') statement = Statement.new(customer, logger)

logger.should_receive(:log).with(/Joe Customer/) statement.print endend

Page 27: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

describe Statement do it "logs a message when printed" do customer = Object.new logger = Object.new customer.stub(:name).and_return('Joe Customer') statement = Statement.new(customer, logger)

logger.should_receive(:log).with(/Joe Customer/) statement.print endend

Page 28: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

method stubdescribe Statement do it "logs a message when printed" do customer = Object.new logger = Object.new customer.stub(:name).and_return('Joe Customer') statement = Statement.new(customer, logger)

logger.should_receive(:log).with(/Joe Customer/) statement.print endend

Page 29: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

describe Statement do it "logs a message when printed" do customer = Object.new logger = Object.new customer.stub(:name).and_return('Joe Customer') statement = Statement.new(customer, logger)

logger.should_receive(:log).with(/Joe Customer/) statement.print endend

Page 30: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

message expectationdescribe Statement do it "logs a message when printed" do customer = Object.new logger = Object.new customer.stub(:name).and_return('Joe Customer') statement = Statement.new(customer, logger)

logger.should_receive(:log).with(/Joe Customer/) statement.print endend

Page 31: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

things aren’t always as they seem

Page 32: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

describe Statement do it "uses the customer name in the header" do customer = mock("customer") statement = Statement.new(customer) customer.should_receive(:name).and_return('Joe Customer')

statement.header.should == "Statement for Joe Customer" endend

class Statement def header "Statement for #{@customer.name}" endend

Page 33: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

describe Statement do it "uses the customer name in the header" do customer = mock("customer") statement = Statement.new(customer) customer.should_receive(:name).and_return('Joe Customer')

statement.header.should == "Statement for Joe Customer" endend

class Statement def header "Statement for #{@customer.name}" endend

Page 34: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

describe Statement do it "uses the customer name in the header" do customer = mock("customer") statement = Statement.new(customer) customer.should_receive(:name).and_return('Joe Customer')

statement.header.should == "Statement for Joe Customer" endend

class Statement def header "Statement for #{@customer.name}" endend

Page 35: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

describe Statement do it "uses the customer name in the header" do customer = mock("customer") statement = Statement.new(customer) customer.should_receive(:name).and_return('Joe Customer')

statement.header.should == "Statement for Joe Customer" endend

class Statement def header "Statement for #{@customer.name}" endend

Page 36: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

describe Statement do it "uses the customer name in the header" do customer = mock("customer") statement = Statement.new(customer) customer.should_receive(:name).and_return('Joe Customer')

statement.header.should == "Statement for Joe Customer" endend

class Statement def header "Statement for #{@customer.name}" endend

messageexpectation

Page 37: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

bound to implementation

describe Statement do it "uses the customer name in the header" do customer = mock("customer") statement = Statement.new(customer) customer.should_receive(:name).and_return('Joe Customer')

statement.header.should == "Statement for Joe Customer" endend

class Statement def header "Statement for #{@customer.name}" endend

Page 38: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

describe Statement do it "uses the customer name in the header" do customer = stub("customer") customer.stub(:name).and_return('Joe Customer') statement = Statement.new(customer)

statement.header.should == "Statement for Joe Customer" endend

class Statement def header "Statement for #{@customer.name}" endend

Page 39: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

describe Statement do it "uses the customer name in the header" do customer = stub("customer") customer.stub(:name).and_return('Joe Customer') statement = Statement.new(customer)

statement.header.should == "Statement for Joe Customer" endend

class Statement def header "Statement for #{@customer.name}" endend

Page 40: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

describe Statement do it "uses the customer name in the header" do customer = stub("customer") customer.stub(:name).and_return('Joe Customer') statement = Statement.new(customer)

statement.header.should == "Statement for Joe Customer" endend

class Statement def header "Statement for #{@customer.name}" endend

Page 41: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

describe Statement do it "uses the customer name in the header" do customer = stub("customer") customer.stub(:name).and_return('Joe Customer') statement = Statement.new(customer)

statement.header.should == "Statement for Joe Customer" endend

class Statement def header "Statement for #{@customer.name}" endend

Page 42: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

describe Statement do it "uses the customer name in the header" do customer = stub("customer") customer.stub(:name).and_return('Joe Customer') statement = Statement.new(customer)

statement.header.should == "Statement for Joe Customer" endend

class Statement def header "Statement for #{@customer.name}" endend

????

Page 43: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

describe Statement do it "uses the customer name in the header" do customer = stub("customer") customer.stub(:name).and_return('Joe Customer') statement = Statement.new(customer)

statement.header.should == "Statement for Joe Customer" endend

class Statement def header "Statement for #{@customer.name}" endend

messageexpectation

Page 44: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

describe Statement do it "uses the customer name in the header" do customer = stub("customer") customer.stub(:name).and_return('Joe Customer') statement = Statement.new(customer)

statement.header.should == "Statement for Joe Customer" endend

class Statement def header "Statement for #{@customer.name}" endend

bound to implementation

Page 45: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

stubs are often used like mocks

Page 46: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

mocks are often used like stubs

Page 47: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

we verify stubs by checking state after

an action

Page 48: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

we tell mocks to verify interactions

Page 49: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

sometimes stubs just make the

system run

Page 50: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

when aremethod stubs

helpful?

Page 51: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

isolation fromnon-determinism

Page 52: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

random values

Page 53: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

random valuesclass BoardTest < MiniTest::Unit::TestCase def test_allows_move_to_last_square board = Board.new( :squares => 50, :die => MiniTest::Mock.new.expect('roll', 2) ) piece = Piece.new

board.place(piece, 48) board.move(piece) assert board.squares[48].contains?(piece) endend

Page 54: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

time

describe Event do it "is not happening before the start time" do now = Time.now start = now + 1 Time.stub(:now).and_return now event = Event.new(:start => start) event.should_not be_happening endend

Page 55: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

isolation fromexternal dependencies

Page 56: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

network access

Subject

DatabaseDatabase Interface

NetworkInterface Internets

Page 57: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

network accessdef test_successful_purchase_sends_shipping_message ActiveMerchant::Billing::Base.mode = :test gateway = ActiveMerchant::Billing::TrustCommerceGateway.new( :login => 'TestMerchant', :password => 'password' ) item = stub() messenger = mock() messenger.expects(:ship).with(item) purchase = Purchase.new(gateway, item, credit_card, messenger) purchase.finalizeend

Page 58: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

network access

Subject

StubDatabase

StubNetwork

CodeExample

Page 59: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

network access

def test_successful_purchase_sends_shipping_message gateway = stub() gateway.stubs(:authorize).returns( ActiveMerchant::Billing::Response.new(true, "ignore") ) item = stub() messenger = mock()

messenger.expects(:ship).with(item) purchase = Purchase.new(gateway, item, credit_card, messenger) purchase.finalizeend

Page 60: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

polymorphic collaborators

Page 61: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

strategies

describe Employee do it "delegates pay() to payment strategy" do payment_strategy = mock() employee = Employee.new(payment_strategy)

payment_strategy.expects(:pay) employee.pay endend

Page 62: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

mixins/pluginsdescribe AgeIdentifiable do describe "#can_vote?" do it "raises if including does not respond to birthdate" do object = Object.new object.extend AgeIdentifiable expect { object.can_vote? }.to raise_error( /must supply a birthdate/ ) end

it "returns true if birthdate == 18 years ago" do object = Object.new stub(object).birthdate {18.years.ago.to_date} object.extend AgeIdentifiable object.can_vote?.should be(true) end endend

Page 63: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

when aremessage expectations

helpful?

Page 64: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

side effectsdescribe Statement do it "logs a message when printed" do customer = stub("customer") customer.stub(:name).and_return('Joe Customer') logger = mock("logger") statement = Statement.new(customer, logger)

logger.should_receive(:log).with(/Joe Customer/) statement.print endend

Page 65: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

cachingdescribe ZipCode do it "should only validate once" do validator = mock() zipcode = ZipCode.new("02134", validator) validator.should_receive(:valid?).with("02134").once. and_return(true) zipcode.valid? zipcode.valid? endend

Page 66: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

interface discoverydescribe "thing I'm working on" do it "does something with some assistance" do thing_i_need = mock() thing_i_am_working_on = ThingIAmWorkingOn.new(thing_i_need)

thing_i_need.should_receive(:help_me).and_return('what I need') thing_i_am_working_on.do_something_complicated endend

Page 67: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

isolation testing

Page 68: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

specifying/testing individual

objects in isolation

Page 69: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

good fit with lots of little objects

Page 70: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls
Page 71: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

all of these concepts apply to

the non-rails specific parts of

our rails apps

Page 72: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

isolation testing the rails-specific parts

of our applicationss

Page 73: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls
Page 74: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

M

C

V

Page 75: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

ViewController

Model

Page 76: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

ViewController

Model

BrowserRouter

Database

Page 77: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

rails testing๏ unit tests

๏ functional tests

๏ integration tests

Page 78: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

rails unit tests๏ model classes (repositories)

๏ model objects

๏ database

Page 79: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

๏ model classes (repositories)

๏ model objects

๏ database

๏ views

๏ controllers

rails functional tests

Page 80: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

๏ model classes (repositories)

๏ model objects

๏ database

๏ views

๏ controllers

rails functional tests

Page 81: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

๏ model classes (repositories)

๏ model objects

๏ database

๏ views

๏ controllers

rails functional tests

!DRY

Page 82: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

rails integration tests๏ model classes (repositories)

๏ model objects

๏ database

๏ views

๏ controllers

๏ routing/sessions

Page 83: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

rails integration tests๏ model classes (repositories)

๏ model objects

๏ database

๏ views

๏ controllers

๏ routing/sessions

!DRY

Page 84: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

the BDD approach

Page 85: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

inherited from XP

Page 86: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

customer specs

developer specs

Page 87: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls
Page 88: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

rails integration tests + webrat

shoulda, context, micronaut, etc

Page 89: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

customer specs are implemented as end to end tests

Page 90: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

developer specs are implemented as

isolation tests

Page 91: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

mocking and stubbingwith rails

Page 92: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

partials in view specsdescribe "/registrations/new.html.erb" do before(:each) do template.stub(:render).with(:partial => anything) end it "renders the registration navigation" do template.should_receive(:render).with(:partial => 'nav') render end it "renders the registration form " do template.should_receive(:render).with(:partial => 'form') render endend

Page 93: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

conditional branches incontroller specs

describe "POST create" do describe "with valid attributes" do it "redirects to list of registrations" do registration = stub_model(Registration) Registration.stub(:new).and_return(registration) registration.stub(:save!).and_return(true) post 'create' response.should redirect_to(registrations_path) end endend

Page 94: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

describe "POST create" do describe "with invalid attributes" do it "re-renders the new form" do registration = stub_model(Registration) Registration.stub(:new).and_return(registration) registration.stub(:save!).and_raise( ActiveRecord::RecordInvalid.new(registration)) post 'create' response.should render_template('new') end endend

conditional branches incontroller specs

Page 95: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

describe "POST create" do describe "with invalid attributes" do it "assigns the registration" do registration = stub_model(Registration) Registration.stub(:new).and_return(registration) registration.stub(:save!).and_raise( ActiveRecord::RecordInvalid.new(registration)) post 'create' assigns[:registration].should equal(registration) end endend

conditional branches incontroller specs

Page 96: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

shave a few lines but leave a little stubble

http://github.com/dchelimsky/stubble

Page 97: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

describe "POST create" do describe "with valid attributes" do it "redirects to list of registrations" do stubbing(Registration) do post 'create' response.should redirect_to(registrations_path) end end endend

stubble

Page 98: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

describe "POST create" do describe "with invalid attributes" do it "re-renders the new form" do stubbing(Registration, :as => :invalid) do post 'create' response.should render_template('new') end end it "assigns the registration" do stubbing(Registration, :as => :invalid) do |registration| post 'create' assigns[:registration].should equal(registration) end end endend

stubble

Page 99: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

chainsdescribe UsersController do it "GET 'best_friend'" do member = stub_model(User) friends = stub() friend = stub_model(User) User.stub(:find).and_return(member) member.stub(:friends).and_return(friends) friends.stub(:favorite).and_return(friend) get :best_friend, :id => '37' assigns[:friend].should equal(friend) endend

Page 100: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

chains

describe UsersController do it "GET 'best_friend'" do friend = stub_model(User) User.stub_chain(:find, :friends, :favorite). and_return(friend) get :best_friend, :id => '37' assigns[:friend].should equal(friend) endend

Page 101: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

guidlines, pitfalls, andcommon concerns

Page 102: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

focus on roles

http://www.jmock.org/oopsla2004.pdf

Mock Roles, not Objects

Page 103: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

keep things simple

Page 104: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

avoid tight coupling

Page 105: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

complex setup is a red flag for design

issues

Page 106: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

don’t stub/mock the object you’re testing

Page 107: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

impedes refactoring

Page 108: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

:refactoring => <<-DEFINITION

Improving design without changing behaviour

DEFINITION

Page 109: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

what is behaviour?

Page 110: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls
Page 111: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

false positivesdescribe RegistrationsController do describe "GET 'pending'" do it "finds the pending registrations" do pending_registration = stub_model(Registration) Registration.should_receive(:pending). and_return([pending_registration]) get 'pending' assigns[:registrations].should == [pending_registration] end endend

class RegistrationsController < ApplicationController def pending @registrations = Registration.pending endend

Page 112: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

false positivesdescribe RegistrationsController do describe "GET 'pending'" do it "finds the pending registrations" do pending_registration = stub_model(Registration) Registration.should_receive(:pending). and_return([pending_registration]) get 'pending' assigns[:registrations].should == [pending_registration] end endend

class RegistrationsController < ApplicationController def pending @registrations = Registration.pending endend

Page 113: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

false positivesdescribe Registration do describe "#pending" do it "finds pending registrations" do Registration.create! Registration.create!(:pending => true) Registration.pending.should have(1).item end endend

class Registration < ActiveRecord::Base named_scope :pending, :conditions => {:pending => true}end

Page 114: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

false positivesdescribe Registration do describe "#pending" do it "finds pending registrations" do Registration.create! Registration.create!(:pending => true) Registration.pending.should have(1).item end endend

class Registration < ActiveRecord::Base named_scope :pending, :conditions => {:pending => true}end

Page 115: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

false positivesdescribe Registration do describe "#pending" do it "finds pending registrations" do Registration.create! Registration.create!(:pending => true) Registration.pending_confirmation.should have(1).item end endend

class Registration < ActiveRecord::Base named_scope :pending_confirmation, :conditions => {:pending => true}end

Page 116: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

false positivesdescribe Registration do describe "#pending" do it "finds pending registrations" do Registration.create! Registration.create!(:pending => true) Registration.pending_confirmation.should have(1).item end endend

class Registration < ActiveRecord::Base named_scope :pending_confirmation, :conditions => {:pending => true}end

Page 117: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

cucumber

Page 118: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls
Page 119: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

http://pragprog.com/titles/achbd/the-rspec-book

http://www.jmock.org/oopsla2004.pdf http://www.mockobjects.com/book/

Mock Roles, not Objectsgrowing object-orientedsoftware, guided by tests

http://xunitpatterns.com/

Page 120: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

http://pragprog.com/titles/achbd/the-rspec-book

http://blog.davidchelimsky.net/http://www.articulatedman.com/

http://rspec.info/http://cukes.info/

Page 121: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

ruby frameworks

Page 122: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

rspec-mocks

http://github.com/dchelimsky/rspec

Page 123: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

mocha

http://github.com/floehopper/mocha

Page 124: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

flexmock

http://github.com/jimweirich/flexmock

Page 126: David Chelimsky Articulated Man, Incassets.en.oreilly.com/1/event/24/Don't Mock... · agenda ๏ overview of stubs and mocks ๏ mocks/stubs applied to rails ๏ guidelines and pitfalls

not a mock

http://github.com/notahat/not_a_mock