Don’t Mock Yourself Out
David Chelimsky Articulated Man, Inc
Dont Mock Yourself Out David Chelimsky Articulated Man, Inc - - PowerPoint PPT Presentation
Dont Mock Yourself Out David Chelimsky Articulated Man, Inc http://martinfowler.com/articles/mocksArentStubs.html Classical and Mockist Testing Classical and Mockist Testing Classical and Mockist Testing classicist mockist merbist
David Chelimsky Articulated Man, Inc
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" end end
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" end end
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" end end
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" end end
describe 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 end end
describe 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 end end
describe 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 end end
describe 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 end end
describe 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 end end
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 end end
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 end end
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 end end
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 end end
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 end end
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 end end
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" end end class Statement def header "Statement for #{@customer.name}" end end
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" end end class Statement def header "Statement for #{@customer.name}" end end
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" end end class Statement def header "Statement for #{@customer.name}" end end
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" end end class Statement def header "Statement for #{@customer.name}" end end
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" end end class Statement def header "Statement for #{@customer.name}" end end
message expectation
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" end end class Statement def header "Statement for #{@customer.name}" end end
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" end end class Statement def header "Statement for #{@customer.name}" end end
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" end end class Statement def header "Statement for #{@customer.name}" end end
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" end end class Statement def header "Statement for #{@customer.name}" end end
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" end end class Statement def header "Statement for #{@customer.name}" end end
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" end end class Statement def header "Statement for #{@customer.name}" end end
????
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" end end class Statement def header "Statement for #{@customer.name}" end end
message expectation
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" end end class Statement def header "Statement for #{@customer.name}" end end
bound to implementation
class 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) end end
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 end end
Subject
Database
Database Interface Network Interface Internets
def 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.finalize end
Subject Stub Database Stub Network Code Example
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.finalize end
describe Employee do it "delegates pay() to payment strategy" do payment_strategy = mock() employee = Employee.new(payment_strategy) payment_strategy.expects(:pay) employee.pay end end
describe AgeIdentifiable do describe "#can_vote?" do it "raises if including does not respond to birthdate" do
expect { object.can_vote? }.to raise_error( /must supply a birthdate/ ) end it "returns true if birthdate == 18 years ago" do
stub(object).birthdate {18.years.ago.to_date}
end end end
describe 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 end end
describe 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? end end
describe "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 end end
describe "/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 end end
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 end end
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 end end
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 end end
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 end end
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 end end
describe 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) end end
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) end end
http://www.jmock.org/oopsla2004.pdf
Mock Roles, not Objects
describe 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 end end class RegistrationsController < ApplicationController def pending @registrations = Registration.pending end end
describe 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 end end class RegistrationsController < ApplicationController def pending @registrations = Registration.pending end end
describe Registration do describe "#pending" do it "finds pending registrations" do Registration.create! Registration.create!(:pending => true) Registration.pending.should have(1).item end end end class Registration < ActiveRecord::Base named_scope :pending, :conditions => {:pending => true} end
describe Registration do describe "#pending" do it "finds pending registrations" do Registration.create! Registration.create!(:pending => true) Registration.pending.should have(1).item end end end class Registration < ActiveRecord::Base named_scope :pending, :conditions => {:pending => true} end
describe Registration do describe "#pending" do it "finds pending registrations" do Registration.create! Registration.create!(:pending => true) Registration.pending_confirmation.should have(1).item end end end class Registration < ActiveRecord::Base named_scope :pending_confirmation, :conditions => {:pending => true} end
describe Registration do describe "#pending" do it "finds pending registrations" do Registration.create! Registration.create!(:pending => true) Registration.pending_confirmation.should have(1).item end end end class Registration < ActiveRecord::Base named_scope :pending_confirmation, :conditions => {:pending => true} end
http://pragprog.com/titles/achbd/the-rspec-book
http://www.jmock.org/oopsla2004.pdf http://www.mockobjects.com/book/
Mock Roles, not Objects growing object-oriented software, guided by tests
http://xunitpatterns.com/