Se ha denunciado esta presentación.
Utilizamos tu perfil de LinkedIn y tus datos de actividad para personalizar los anuncios y mostrarte publicidad más relevante. Puedes cambiar tus preferencias de publicidad en cualquier momento.
MOCKS VS STUBS  - How will we test this?
WHO AM I?•   Attila Domokos•   .NET Programmer•   Ruby Enthusiast•   Twitter: @adomokos•   Blog: http://www.adomokos.com• ...
WHO...??
MOCKS AREN’T STUBS
THE WAREHOUSE EXAMPLE
CALL SEQUENCES
describe Order do  before(:each) do    @warehouse = Warehouse.new    @warehouse.add(:Cleveland, 50)    @warehouse.add(:Akr...
USING A MOCKdescribe Order do  it "fills the order with enough items in warehouse" do    order = Order.new(:Cleveland, 50)...
USING A MOCKdescribe Order do  it "fills the order with enough items in warehouse" do    order = Order.new(:Cleveland, 50)...
USING A STUB - VERBOSEdescribe Order do  it "fills the order with enough items in warehouse" do    @warehouse.stub!(:quant...
describe Order do  before(:each) do    @warehouse = stub(warehouse_stub)    setup_stub  end it "fills the order with enoug...
HOW COOL IS THAT?describe Order do  before(:each) do    @warehouse = stub(warehouse_stub,         {:quantity_at => 50, :se...
CAN WE DO THE SAME?describe Order do  it "fills the order with enough items in warehouse" do    order = Order.new(:Clevela...
OH, SNAP!describe Order do  it "fills the order with enough items in warehouse" do    order = Order.new(:Cleveland, 50)   ...
BUT THIS WORKS!describe Order do  it "fills the order with enough items in warehouse" do    order = Order.new(:Cleveland, ...
BUT THIS WORKS!describe Order do  it "fills the order with enough items in warehouse" do    order = Order.new(:Cleveland, ...
SO WHAT’S THE DIFFERENCE?
NO, SERIOUSLY!•   Stubs - Provide canned responses to messages•   Mocks - Specify AND verify that certain messages should ...
MOCKS CAN DO MORE!Expecting Messages:  my_mock.should_receive(:msg).once  my_mock.should_not_receive(:msg).onceExpecting A...
MOCKS CAN DO MOREdescribe Order do  it "fills the order with enough items in warehouse" do    order = Order.new(:Cleveland...
MOCKS CAN DO MOREdescribe Order do  it "fills the order with enough items in warehouse" do    order = Order.new(:Cleveland...
CHANGE THE ORDERdescribe Order do  it "fills the order with enough items in warehouse" do    order = Order.new(:Cleveland,...
OH, SNAP!describe Order do  it "fills the order with enough items in warehouse" do    order = Order.new(:Cleveland, 50)   ...
I USED RSPEC MOCKING...     ... but there are other libraries:•   Flexmock•   Mocha•   rr
FLEXMOCK - TEST/UNITclass TestOrder < Test::Unit::TestCase  def test_fills_order_with_enough_items_at_location    order = ...
FLEXMOCK - TEST/UNITclass TestOrder < Test::Unit::TestCase  def test_fills_order_with_enough_items_at_location    order = ...
WHEN TO USE MOCKS/STUBS?•   Using an external service•   Verifying a protocol•   Objects are complicated to create
WHEN TO USE MOCKS/STUBS?•   Using an external service•   Verifying a protocol•   Objects are complicated to create
BUT HOWCAN I USE  THIS?
MEET TWEETSTATS
TWITTER OAUTH
LOGGED ON
SEND TWEET
VIEW FRIENDS
VIEW FOLLOWERS
ENTER THE SERVICEModel         ControllerView                      OauthService
THE USERS CONTROLLERclass UsersController < ApplicationController  before_filter :oauth_login_required,                 :e...
STUB IT OUT!describe UsersController do  TEST_URL = twitter_test  describe "GET new" do    it "redirects to twitter - stub...
STUB IT OUT!describe UsersController do  TEST_URL = twitter_test  describe "GET new" do    it "redirects to twitter - stub...
OR MOCK ITdescribe UsersController do  TEST_URL = twitter_test.com  describe "GET new" do    it "redirects to twitter - st...
OR MOCK ITdescribe UsersController do  TEST_URL = twitter_test.com  describe "GET new" do    it "redirects to twitter - st...
BUT WHAT’S THE DIFFERENCE?                            Unused Message Stuboauth_service_stub =    stub(:login_by_oauth => T...
THIS WILL FAILit "redirects to twitter - mock example" do  oauth_service_mock = mock(:oauth_service)  oauth_service_mock  ...
OH, SNAP!it "redirects to twitter - mock example" do  oauth_service_mock = mock(:oauth_service)  oauth_service_mock       ...
OK, I AM AUTHENTICATEDdef callback  user_info =    self.oauth_service.get_user_info(params[:oauth_verifier])  @user = User...
A NEGATIVE TESTdescribe "Get callback" do  it "redirects to the home page when error occurs in service" do    # I can use ...
A NEGATIVE TESTdescribe "Get callback" do  it "redirects to the home page when error occurs in service" do    # I can use ...
OR EXPECT IT TWICEdescribe "Get callback" do  it "redirects to the home page when error occurs in service" do    # I can u...
OH, SNAP!describe "Get callback" do  it "redirects to the home page when error occurs in service" do    # I can use a mock...
A STUB WILL BE FINEdescribe "Get callback" do  it "redirects to the home page when error occurs in service" do    # I coul...
A STUB WILL BE FINEdescribe "Get callback" do  it "redirects to the home page when error occurs in service" do    # I coul...
A POSITIVE TESTit "redirects to the users page after a successful login" do  user_info_stub = {id => 123456, screen_name =...
A POSITIVE TESTit "redirects to the users page after a successful login" do  user_info_stub = {id => 123456, screen_name =...
CHECK THE ARGUMENTit "redirects to the users page after a successful login" do  user_info_stub = {id => 123456, screen_nam...
OH, SNAP!it "redirects to the users page after a successful login" do  user_info_stub = {id => 123456, screen_name => john...
AND THE CUCUMBER?
USER LOGIN FEATUREFeature: Login Users  In order to access the full site  As a user  I want to log on to the site with my ...
USER LOGIN FEATUREFeature: Login Users  In order to access the full site  As a user  I want to log on to the site with my ...
WHAT OPTIONS DO I HAVE?•   Hit Twitter every time•   Stub out my service object•   Stub out HTTP
WHAT OPTIONS DO I HAVE?•   Hit Twitter every time•   Stub out my service object•   Stub out HTTP                Run test o...
USER_LOGIN_STEPS.RB  Scenario: Login via Twitter    Given I am on the home page    When I follow "sign_in_with_twitter"   ...
ENV.RBrequire fakewebFakeWeb.register_uri(:get,          http://twitter.com/oauth/authorize?oauth_token=fake,          :bo...
NEVER GO OUTSIDE!require fakewebFakeWeb.allow_net_connect = falseFakeWeb.register_uri(:get,          http://twitter.com/oa...
VIEW FRIENDS
FRIENDS FEATUREFeature: View Friends  In order to see who my friends are  As a user  I want to go to the friends page and ...
THE STEPSGiven /^I am logged on to the site$/ do  visit callback_users_path                     view_friends_steps.rbend  ...
CHUCK NORRIS IS HAPPY!
RECAP• Stubs    are “Yugos”, Mocks are “Aston Martins”• Stubs    are canned answered to messages• Mocks     can verify:   ...
MOCKS CAN DO MORE!Expecting Messages:  my_mock.should_receive(:msg).once  my_mock.should_not_receive(:msg).onceExpecting A...
THANK YOU!
REFERENCES•   http://keremerkan.net/qr-code-and-2d-code-generator•   http://martinfowler.com/articles/mocksArentStubs.html...
Mock vs Stubs CleRB Presentation
Mock vs Stubs CleRB Presentation
Próxima SlideShare
Cargando en…5
×

Mock vs Stubs CleRB Presentation

2.838 visualizaciones

Publicado el

"Mocks vs Stubs" Cleveland Ruby Brigade (CleRB) Presentation

Publicado en: Tecnología
  • DOWNLOAD FULL. BOOKS INTO AVAILABLE FORMAT ......................................................................................................................... ......................................................................................................................... 1.DOWNLOAD FULL. PDF EBOOK here { https://tinyurl.com/y8nn3gmc } ......................................................................................................................... 1.DOWNLOAD FULL. EPUB Ebook here { https://tinyurl.com/y8nn3gmc } ......................................................................................................................... 1.DOWNLOAD FULL. doc Ebook here { https://tinyurl.com/y8nn3gmc } ......................................................................................................................... 1.DOWNLOAD FULL. PDF EBOOK here { https://tinyurl.com/y8nn3gmc } ......................................................................................................................... 1.DOWNLOAD FULL. EPUB Ebook here { https://tinyurl.com/y8nn3gmc } ......................................................................................................................... 1.DOWNLOAD FULL. doc Ebook here { https://tinyurl.com/y8nn3gmc } ......................................................................................................................... ......................................................................................................................... ......................................................................................................................... .............. Browse by Genre Available eBooks ......................................................................................................................... Art, Biography, Business, Chick Lit, Children's, Christian, Classics, Comics, Contemporary, Cookbooks, Crime, Ebooks, Fantasy, Fiction, Graphic Novels, Historical Fiction, History, Horror, Humor And Comedy, Manga, Memoir, Music, Mystery, Non Fiction, Paranormal, Philosophy, Poetry, Psychology, Religion, Romance, Science, Science Fiction, Self Help, Suspense, Spirituality, Sports, Thriller, Travel, Young Adult,
       Responder 
    ¿Estás seguro?    No
    Tu mensaje aparecerá aquí

Mock vs Stubs CleRB Presentation

  1. 1. MOCKS VS STUBS - How will we test this?
  2. 2. WHO AM I?• Attila Domokos• .NET Programmer• Ruby Enthusiast• Twitter: @adomokos• Blog: http://www.adomokos.com• Email:
  3. 3. WHO...??
  4. 4. MOCKS AREN’T STUBS
  5. 5. THE WAREHOUSE EXAMPLE
  6. 6. CALL SEQUENCES
  7. 7. describe Order do before(:each) do @warehouse = Warehouse.new @warehouse.add(:Cleveland, 50) @warehouse.add(:Akron, 25) end it "fills the order with enough items in warehouse" do order = Order.new(:Cleveland, 50) order.fill(@warehouse) order.should be_filled @warehouse.quantity_at(:Cleveland).should == 0 end it "does not fill the order with not enough items" do order = Order.new(:Cleveland, 51) order.fill(@warehouse) order.should_not be_filled @warehouse.quantity_at(:Cleveland).should == 50 endend
  8. 8. USING A MOCKdescribe Order do it "fills the order with enough items in warehouse" do order = Order.new(:Cleveland, 50) warehouse = mock(:warehouse) warehouse.should_receive(:quantity_at).with(:Cleveland).and_return(50) warehouse.should_receive(:set_quantity_at).with(:Cleveland, 0) order.fill(warehouse) order.should be_filled end it "does not fill the order with not enough items" do order = Order.new(:Cleveland, 51) warehouse = mock(:warehouse) warehouse.should_receive(:quantity_at).with(:Cleveland).and_return(50) order.fill(warehouse) order.should_not be_filled endend
  9. 9. USING A MOCKdescribe Order do it "fills the order with enough items in warehouse" do order = Order.new(:Cleveland, 50) warehouse = mock(:warehouse) warehouse.should_receive(:quantity_at).with(:Cleveland).and_return(50) warehouse.should_receive(:set_quantity_at).with(:Cleveland, 0) order.fill(warehouse) order.should be_filled end it "does not fill the order with not enough items" do order = Order.new(:Cleveland, 51) warehouse = mock(:warehouse) warehouse.should_receive(:quantity_at).with(:Cleveland).and_return(50) order.fill(warehouse) order.should_not be_filled endend
  10. 10. USING A STUB - VERBOSEdescribe Order do it "fills the order with enough items in warehouse" do @warehouse.stub!(:quantity_at).and_return(50) @warehouse.stub!(:set_quantity_at).and_return(true) order = Order.new(:Cleveland, 50) order.fill(@warehouse) order.should be_filled end it "does not fill the order with not enough items" do @warehouse.stub!(:quantity_at).and_return(50) @warehouse.stub!(:set_quantity_at).and_return(true) order = Order.new(:Cleveland, 51) order.fill(@warehouse) order.should_not be_filled endend
  11. 11. describe Order do before(:each) do @warehouse = stub(warehouse_stub) setup_stub end it "fills the order with enough items in warehouse" do order = Order.new(:Cleveland, 50) order.fill(@warehouse) order.should be_filled end it "does not fill the order with not enough items" do order = Order.new(:Cleveland, 51) order.fill(@warehouse) order.should_not be_filled endenddef setup_stub @warehouse.stub!(:quantity_at).and_return(50) @warehouse.stub!(:set_quantity_at).and_return(true)end
  12. 12. HOW COOL IS THAT?describe Order do before(:each) do @warehouse = stub(warehouse_stub, {:quantity_at => 50, :set_quantity_at => true}) end it "fills the order with enough items in warehouse" do order = Order.new(:Cleveland, 50) order.fill(@warehouse) order.should be_filled end it "does not fill the order with not enough items" do order = Order.new(:Cleveland, 51) order.fill(@warehouse) order.should_not be_filled endend
  13. 13. CAN WE DO THE SAME?describe Order do it "fills the order with enough items in warehouse" do order = Order.new(:Cleveland, 50) warehouse = mock(:warehouse) warehouse.should_receive(:quantity_at).with(:Cleveland).and_return(50) warehouse.should_receive(:set_quantity_at).with(:Cleveland, 0) order.fill(warehouse) order.should be_filled end it "does not fill the order with not enough items" do order = Order.new(:Cleveland, 51) warehouse = mock(:warehouse) warehouse.should_receive(:quantity_at).with(:Cleveland).and_return(50) warehouse.should_receive(:set_quantity_at).with(:Cleveland, 0) order.fill(warehouse) order.should_not be_filled endend
  14. 14. OH, SNAP!describe Order do it "fills the order with enough items in warehouse" do order = Order.new(:Cleveland, 50) warehouse = mock(:warehouse) warehouse.should_receive(:quantity_at).with(:Cleveland).and_return(50) warehouse.should_receive(:set_quantity_at).with(:Cleveland, 0) order.fill(warehouse) order.should be_filled end it "does not fill the order with not enough items" do order = Order.new(:Cleveland, 51) warehouse = mock(:warehouse) warehouse.should_receive(:quantity_at).with(:Cleveland).and_return(50) warehouse.should_receive(:set_quantity_at).with(:Cleveland, 0) order.fill(warehouse) order.should_not be_filled endend
  15. 15. BUT THIS WORKS!describe Order do it "fills the order with enough items in warehouse" do order = Order.new(:Cleveland, 50) warehouse = mock(:warehouse) warehouse.should_receive(:quantity_at).with(:Cleveland).and_return(50) warehouse.should_receive(:set_quantity_at).with(:Cleveland, 0) order.fill(warehouse) order.should be_filled end it "does not fill the order with not enough items" do order = Order.new(:Cleveland, 51) warehouse = mock(:warehouse) warehouse.should_receive(:quantity_at).with(:Cleveland).and_return(50) warehouse.should_not_receive(:set_quantity_at).with(:Cleveland, 0) order.fill(warehouse) order.should_not be_filled endend
  16. 16. BUT THIS WORKS!describe Order do it "fills the order with enough items in warehouse" do order = Order.new(:Cleveland, 50) warehouse = mock(:warehouse) warehouse.should_receive(:quantity_at).with(:Cleveland).and_return(50) warehouse.should_receive(:set_quantity_at).with(:Cleveland, 0) order.fill(warehouse) order.should be_filled end it "does not fill the order with not enough items" do order = Order.new(:Cleveland, 51) warehouse = mock(:warehouse) warehouse.should_receive(:quantity_at).with(:Cleveland).and_return(50) warehouse.should_not_receive(:set_quantity_at).with(:Cleveland, 0) order.fill(warehouse) order.should_not be_filled endend
  17. 17. SO WHAT’S THE DIFFERENCE?
  18. 18. NO, SERIOUSLY!• Stubs - Provide canned responses to messages• Mocks - Specify AND verify that certain messages should be received
  19. 19. MOCKS CAN DO MORE!Expecting Messages: my_mock.should_receive(:msg).once my_mock.should_not_receive(:msg).onceExpecting Arguments: my_mock.should_receive(:msg).with(1, 2) my_mock.should_receive(:msg).with(no_args()) my_mock.should_receive(:msg).with(any_args())Argument Constraints: my_mock.should_receive(:msg).with(1, an_instance_of(Fixnum), “b”) my_mock.should_receive(:msg).with(a, boolean(), b) my_mock.should_receive(:msg).with(/abc/)Receive Counts: my_mock.should_receive(:msg).once my_mock.should_receive(:msg).twice my_mock.should_receive(:msg).at_least(:once) my_mock.should_receive(:msg).at_most(:twice) my_mock.should_receive(:msg).any_number_of_timesOrdering: my_mock.should_receive(:one).ordered my_mock.should_receive(:two).ordered
  20. 20. MOCKS CAN DO MOREdescribe Order do it "fills the order with enough items in warehouse" do order = Order.new(:Cleveland, 50) warehouse = mock(:warehouse)warehouse.should_receive(:quantity_at).ordered.with(:Cleveland).and_return(50) warehouse.should_receive(:set_quantity_at).ordered.with(:Cleveland, 0) order.fill(warehouse) order.should be_filled endend
  21. 21. MOCKS CAN DO MOREdescribe Order do it "fills the order with enough items in warehouse" do order = Order.new(:Cleveland, 50) warehouse = mock(:warehouse)warehouse.should_receive(:quantity_at).ordered.with(:Cleveland).and_return(50) warehouse.should_receive(:set_quantity_at).ordered.with(:Cleveland, 0) order.fill(warehouse) order.should be_filled endend
  22. 22. CHANGE THE ORDERdescribe Order do it "fills the order with enough items in warehouse" do order = Order.new(:Cleveland, 50) warehouse = mock(:warehouse) warehouse.should_receive(:set_quantity_at).ordered.with(:Cleveland, 0) warehouse.should_receive(:quantity_at).ordered .with(:Cleveland).and_return(50) order.fill(warehouse) order.should be_filled endend
  23. 23. OH, SNAP!describe Order do it "fills the order with enough items in warehouse" do order = Order.new(:Cleveland, 50) warehouse = mock(:warehouse) warehouse.should_receive(:set_quantity_at).ordered.with(:Cleveland, 0) warehouse.should_receive(:quantity_at).ordered .with(:Cleveland).and_return(50) order.fill(warehouse) order.should be_filled endend
  24. 24. I USED RSPEC MOCKING... ... but there are other libraries:• Flexmock• Mocha• rr
  25. 25. FLEXMOCK - TEST/UNITclass TestOrder < Test::Unit::TestCase def test_fills_order_with_enough_items_at_location order = Order.new(:Cleveland, 50) warehouse = flexmock(warehouse) warehouse.should_receive(:quantity_at).with(:Cleveland).and_return(50) warehouse.should_receive(:set_quantity_at).with(:Cleveland, 0) order.fill(warehouse) assert order.filled? end def test_does_not_fill_order_with_not_enough_items_at_location order = Order.new(:Cleveland, 51) warehouse = flexmock(warehouse) warehouse.should_receive(:quantity_at).with(:Cleveland).and_return(50) order.fill(warehouse) assert order.filled? == false endend
  26. 26. FLEXMOCK - TEST/UNITclass TestOrder < Test::Unit::TestCase def test_fills_order_with_enough_items_at_location order = Order.new(:Cleveland, 50) warehouse = flexmock(warehouse) warehouse.should_receive(:quantity_at).with(:Cleveland).and_return(50) warehouse.should_receive(:set_quantity_at).with(:Cleveland, 0) order.fill(warehouse) assert order.filled? end def test_does_not_fill_order_with_not_enough_items_at_location order = Order.new(:Cleveland, 51) warehouse = flexmock(warehouse) warehouse.should_receive(:quantity_at).with(:Cleveland).and_return(50) order.fill(warehouse) assert order.filled? == false endend
  27. 27. WHEN TO USE MOCKS/STUBS?• Using an external service• Verifying a protocol• Objects are complicated to create
  28. 28. WHEN TO USE MOCKS/STUBS?• Using an external service• Verifying a protocol• Objects are complicated to create
  29. 29. BUT HOWCAN I USE THIS?
  30. 30. MEET TWEETSTATS
  31. 31. TWITTER OAUTH
  32. 32. LOGGED ON
  33. 33. SEND TWEET
  34. 34. VIEW FRIENDS
  35. 35. VIEW FOLLOWERS
  36. 36. ENTER THE SERVICEModel ControllerView OauthService
  37. 37. THE USERS CONTROLLERclass UsersController < ApplicationController before_filter :oauth_login_required, :except => [ :callback, :signout, :index ] def new end...private def oauth_login_required logged_in? || login_by_oauth end... def login_by_oauth redirect_to self.oauth_service.login_by_oauth rescue Exception => e # The user might have rejected this application flash[:error] = "Twitter API failure (account login)" redirect_to root_url endend
  38. 38. STUB IT OUT!describe UsersController do TEST_URL = twitter_test describe "GET new" do it "redirects to twitter - stub example" do # see the extra message stub, I dont need “logged_in?” oauth_service_stub = stub(:login_by_oauth => TEST_URL, :logged_in? => false) controller .stub!(:oauth_service) .and_return(oauth_service_stub) get new response.should redirect_to TEST_URL end endend
  39. 39. STUB IT OUT!describe UsersController do TEST_URL = twitter_test describe "GET new" do it "redirects to twitter - stub example" do # see the extra message stub, I dont need “logged_in?” oauth_service_stub = stub(:login_by_oauth => TEST_URL, :logged_in? => false) controller .stub!(:oauth_service) .and_return(oauth_service_stub) get new response.should redirect_to TWITTER_TEST_URL end endend
  40. 40. OR MOCK ITdescribe UsersController do TEST_URL = twitter_test.com describe "GET new" do it "redirects to twitter - stub example" do ... end it "redirects to twitter - mock example" do oauth_service_mock = mock(:oauth_service) oauth_service_mock .should_receive(:login_by_oauth) .and_return(TEST_URL) controller .stub!(:oauth_service).and_return(oauth_service_mock) get new response.should redirect_to TEST_URL end endend
  41. 41. OR MOCK ITdescribe UsersController do TEST_URL = twitter_test.com describe "GET new" do it "redirects to twitter - stub example" do ... end it "redirects to twitter - mock example" do oauth_service_mock = mock(:oauth_service) oauth_service_mock .should_receive(:login_by_oauth) .and_return(TEST_URL) controller .stub!(:oauth_service).and_return(oauth_service_mock) get new response.should redirect_to TEST_URL end endend
  42. 42. BUT WHAT’S THE DIFFERENCE? Unused Message Stuboauth_service_stub = stub(:login_by_oauth => TEST_URL, :logged_in? => false) oauth_service_mock = mock(:oauth_service) oauth_service_mock .should_receive(:login_by_oauth) .and_return(TEST_URL)
  43. 43. THIS WILL FAILit "redirects to twitter - mock example" do oauth_service_mock = mock(:oauth_service) oauth_service_mock .should_receive(:login_by_oauth) .and_return(TEST_URL) oauth_service_mock .should_receive(:logged_in) .and_return(false) controller .stub!(:oauth_service).and_return(oauth_service_mock) get new response.should redirect_to TEST_URLend
  44. 44. OH, SNAP!it "redirects to twitter - mock example" do oauth_service_mock = mock(:oauth_service) oauth_service_mock .should_receive(:login_by_oauth) .and_return(TEST_URL) oauth_service_mock .should_receive(:logged_in) .and_return(false) controller .stub!(:oauth_service).and_return(oauth_service_mock) get new response.should redirect_to TEST_URLend
  45. 45. OK, I AM AUTHENTICATEDdef callback user_info = self.oauth_service.get_user_info(params[:oauth_verifier]) @user = User.save_user!({ :twitter_id => user_info[id], :screen_name => user_info[screen_name], :token => self.oauth_service.access_token, :secret => self.oauth_service.access_secret, :profile_image_url => user_info[profile_image_url] }) self.current_user = @user redirect_to @user # Redirect to the show pagerescue Exception => e # The user might have rejected this application. flash[:error] = "Twitter API failure (account login)" redirect_to root_urlend
  46. 46. A NEGATIVE TESTdescribe "Get callback" do it "redirects to the home page when error occurs in service" do # I can use a mock oauth_service = mock(:oauth_service) oauth_service.should_receive(:get_user_info) .once .with(xyz) .and_raise(StandardError) controller.stub!(:oauth_service).and_return(oauth_service) # Exercise get callback, {:oauth_verifier => xyz} flash[:error].should == Twitter API failure (account login) response.should redirect_to root_url endend
  47. 47. A NEGATIVE TESTdescribe "Get callback" do it "redirects to the home page when error occurs in service" do # I can use a mock oauth_service = mock(:oauth_service) oauth_service.should_receive(:get_user_info) .once .with(xyz) .and_raise(StandardError) controller.stub!(:oauth_service).and_return(oauth_service) # Exercise get callback, {:oauth_verifier => xyz} flash[:error].should == Twitter API failure (account login) response.should redirect_to root_url endend
  48. 48. OR EXPECT IT TWICEdescribe "Get callback" do it "redirects to the home page when error occurs in service" do # I can use a mock oauth_service = mock(:oauth_service) oauth_service.should_receive(:get_user_info) .twice .with(xyz) .and_raise(StandardError) controller.stub!(:oauth_service).and_return(oauth_service) # Exercise get callback, {:oauth_verifier => xyz} flash[:error].should == Twitter API failure (account login) response.should redirect_to root_url endend
  49. 49. OH, SNAP!describe "Get callback" do it "redirects to the home page when error occurs in service" do # I can use a mock oauth_service = mock(:oauth_service) oauth_service.should_receive(:get_user_info) .twice .with(xyz) .and_raise(StandardError) controller.stub!(:oauth_service).and_return(oauth_service) # Exercise get callback, {:oauth_verifier => xyz} flash[:error].should == Twitter API failure (account login) response.should redirect_to root_url endend
  50. 50. A STUB WILL BE FINEdescribe "Get callback" do it "redirects to the home page when error occurs in service" do # I could use a mock # oauth_service = mock(:oauth_service) # oauth_service.should_receive(:get_user_info) .once.with(xyz) .and_raise(StandardError) # but a stub will exercise the code just fine oauth_service = stub(:oauth_service) oauth_service.stub!(:get_user_info).and_raise(StandardError) controller.stub!(:oauth_service).and_return(oauth_service) # Exercise get callback, {:oauth_verifier => xyz} flash[:error].should == Twitter API failure (account login) response.should redirect_to root_url endend
  51. 51. A STUB WILL BE FINEdescribe "Get callback" do it "redirects to the home page when error occurs in service" do # I could use a mock # oauth_service = mock(:oauth_service) # oauth_service.should_receive(:get_user_info) .once.with(xyz) .and_raise(StandardError) # but a stub will exercise the code just fine oauth_service = stub(:oauth_service) oauth_service.stub!(:get_user_info).and_raise(StandardError) controller.stub!(:oauth_service).and_return(oauth_service) # Exercise get callback, {:oauth_verifier => xyz} flash[:error].should == Twitter API failure (account login) response.should redirect_to root_url endend
  52. 52. A POSITIVE TESTit "redirects to the users page after a successful login" do user_info_stub = {id => 123456, screen_name => johndoe, profile_image_url => some_image_url} oauth_service_mock = mock(OauthService, :access_token => 12345, :access_secret => abcde) fake oauth_service_mock.should_receive(:get_user_info) .with(xyz) .and_return(user_info_stub) stub user = User.new dummy mock User.stub!(:save_user!).and_return(user) controller.stub!(:oauth_service).and_return(oauth_service_mock) # Exercise get callback, {:oauth_verifier => xyz} controller.current_user.should == user response.should redirect_to userend
  53. 53. A POSITIVE TESTit "redirects to the users page after a successful login" do user_info_stub = {id => 123456, screen_name => johndoe, profile_image_url => some_image_url} oauth_service_mock = mock(OauthService, :access_token => 12345, :access_secret => abcde) fake oauth_service_mock.should_receive(:get_user_info) .with(xyz) .and_return(user_info_stub) stub user = User.new(:id => 122) dummy mock User.stub!(:save_user!).and_return(user) controller.stub!(:oauth_service).and_return(oauth_service_mock) # Exercise get callback, {:oauth_verifier => xyz} controller.current_user.should == user response.should redirect_to userend
  54. 54. CHECK THE ARGUMENTit "redirects to the users page after a successful login" do user_info_stub = {id => 123456, screen_name => johndoe, profile_image_url => some_image_url} oauth_service_mock = mock(OauthService, :access_token => 12345, :access_secret => abcde) oauth_service_mock.should_receive(:get_user_info) .with(abc) .and_return(user_info_stub) user = User.new(:id => 122) User.stub!(:save_user!).and_return(user) controller.stub!(:oauth_service).and_return(oauth_service_mock) # Exercise get callback, {:oauth_verifier => xyz} controller.current_user.should == user response.should redirect_to userend
  55. 55. OH, SNAP!it "redirects to the users page after a successful login" do user_info_stub = {id => 123456, screen_name => johndoe, profile_image_url => some_image_url} oauth_service_mock = mock(OauthService, :access_token => 12345, :access_secret => abcde) oauth_service_mock.should_receive(:get_user_info) .with(abc) .and_return(user_info_stub) user = User.new(:id => 122) User.stub!(:save_user!).and_return(user) controller.stub!(:oauth_service).and_return(oauth_service_mock) # Exercise get callback, {:oauth_verifier => xyz} controller.current_user.should == user response.should redirect_to userend
  56. 56. AND THE CUCUMBER?
  57. 57. USER LOGIN FEATUREFeature: Login Users In order to access the full site As a user I want to log on to the site with my twitter account Scenario: Login via Twitter Given I am on the home page When I follow "sign_in_with_twitter" And Twitter authorizes me Then I should see "Welcome back!"
  58. 58. USER LOGIN FEATUREFeature: Login Users In order to access the full site As a user I want to log on to the site with my twitter account Scenario: Login via Twitter Given I am on the home page When I follow "sign_in_with_twitter" And Twitter authorizes me Then I should see "Welcome back!"
  59. 59. WHAT OPTIONS DO I HAVE?• Hit Twitter every time• Stub out my service object• Stub out HTTP
  60. 60. WHAT OPTIONS DO I HAVE?• Hit Twitter every time• Stub out my service object• Stub out HTTP Run test offline mode
  61. 61. USER_LOGIN_STEPS.RB Scenario: Login via Twitter Given I am on the home page When I follow "sign_in_with_twitter" And Twitter authorizes me Then I should see "Welcome back!" When /^Twitter authorizes me$/ do visit callback_users_path end
  62. 62. ENV.RBrequire fakewebFakeWeb.register_uri(:get, http://twitter.com/oauth/authorize?oauth_token=fake, :body => success)FakeWeb.register_uri(:post, http://twitter.com/oauth/access_token, :body => oauth_token=fake&oauth_token_secret=fake)FakeWeb.register_uri(:get, http://twitter.com/account/verify_credentials.json, :response => File.join(::Rails.root.to_s, features, fixtures, verify_credentials.json))
  63. 63. NEVER GO OUTSIDE!require fakewebFakeWeb.allow_net_connect = falseFakeWeb.register_uri(:get, http://twitter.com/oauth/authorize?oauth_token=fake, :body => success)FakeWeb.register_uri(:post, http://twitter.com/oauth/access_token, :body => oauth_token=fake&oauth_token_secret=fake)FakeWeb.register_uri(:get, http://twitter.com/account/verify_credentials.json, :response => File.join(::Rails.root.to_s, features, fixtures, verify_credentials.json))
  64. 64. VIEW FRIENDS
  65. 65. FRIENDS FEATUREFeature: View Friends In order to see who my friends are As a user I want to go to the friends page and see my friends Background: Given I am logged on to the site Scenario: View friends When I follow "friends" Then I should see "You are following 4 friends."
  66. 66. THE STEPSGiven /^I am logged on to the site$/ do visit callback_users_path view_friends_steps.rbend $: curl -is http://twitter.com/statuses/friends.json? screen_name=adomokos&cursor=-1 > features/fixtures/friends.jsonFakeWeb.register_uri(:get, http://twitter.com/statuses/friends.json?screen_name=adomokos&cursor=-1, :response => File.join(::Rails.root.to_s, features, fixtures, friends.json)) env.rb
  67. 67. CHUCK NORRIS IS HAPPY!
  68. 68. RECAP• Stubs are “Yugos”, Mocks are “Aston Martins”• Stubs are canned answered to messages• Mocks can verify: • If message was sent or not • Input parameters • Order of message• Never go outside of your “box” during automated tests!
  69. 69. MOCKS CAN DO MORE!Expecting Messages: my_mock.should_receive(:msg).once my_mock.should_not_receive(:msg).onceExpecting Arguments: my_mock.should_receive(:msg).with(1, 2) my_mock.should_receive(:msg).with(no_args()) my_mock.should_receive(:msg).with(any_args())Argument Constraints: my_mock.should_receive(:msg).with(1, an_instance_of(Fixnum), “b”) my_mock.should_receive(:msg).with(a, boolean(), b) my_mock.should_receive(:msg).with(/abc/)Receive Counts: my_mock.should_receive(:msg).once my_mock.should_receive(:msg).twice my_mock.should_receive(:msg).at_least(:once) my_mock.should_receive(:msg).at_most(:twice) my_mock.should_receive(:msg).any_number_of_timesOrdering: my_mock.should_receive(:one).ordered my_mock.should_receive(:two).ordered
  70. 70. THANK YOU!
  71. 71. REFERENCES• http://keremerkan.net/qr-code-and-2d-code-generator• http://martinfowler.com/articles/mocksArentStubs.html• http://blog.zerosum.org/2009/7/13/twitter-auth-integration- testing• http://dev.twitter.com/console• http://rspec.info/documentation/mocks/ message_expectations.html

×