staying fast and furious

staying fast and furious

The slide deck for a talk on leaner/faster tests presented at Being-Agile 2013 conference held in Gurgaon.

E2143258b0228b454fa4b63d406243f3?s=128

Avinash Chugh

March 15, 2013
Tweet

Transcript

  1. Staying fast and furious Leaner tests for your Rails application

    http://handras.hu/uploads/Dodge-Charger-Classic.jpg
  2. it’s not unusual. rails 3.x ruby-oci8 rspec mocha factory_girl cucumber

    http://www.librarising.com/astrology/celebs/images2/T-Z/tomjones.jpg
  3. slow tests are wrong. you waste time waiting for them

    to finish you don’t run them often your commits are more likely to break things you lose focus from what you need to do http://xkcd.com/303/
  4. speed is good. focus faster feedback real rush the right

    thing “If everything seems under control, you’re not going fast enough.” -Mario Andretti
  5. where do you start? $ cat .rspec --colour --profile $

    cat lib/tasks/spec.rake RSpec::Core::RakeTask.new(:rcov) do |spec| spec.pattern = 'spec/**/*_spec.rb' spec.rspec_opts = ["--profile"] spec.rcov = true end track the 10 slowest examples $ bundle exec rake spec --profile
  6. profiling on!

  7. clearing your junk. transactions vs. truncation http://i-cdn.apartmenttherapy.com/uimages/sf/011311-junk.jpg

  8. slow features. @javascript Scenario: Changing my profile When I fill

    in my contact details Then I should see these on my profile When I change my contact details Then I should see these on my profile Cucumber::Rails::Database.javascript_strategy = :truncation
  9. use transactional fixtures unless you really can’t

  10. avoid truncation it 'should pass' do Object.new.should_not be_nil end

  11. before :all or :each http://www.discoverwoodlandhills.com/images/InTheBeginningLIGHT.jpg

  12. authentication controller. describe AuthController do before do stub_warden login_as Factory(:user_with_rights)

    end it 'should login' do AuthController.any_instance.stubs(:new_token).returns('12345') post :authenticate, :username => 'john', :password => 'password' JSON.parse(response.body)['token'].should == '12345' end it 'should deny login' do AuthController.any_instance.stubs(:new_token).returns(nil) post :authenticate, :username => 'john', :password => 'any-other-password' response.status.should == '403 Forbidden'.to_i end ... end
  13. authentication controller. describe AuthController do before :all do @user =

    Factory(:user_with_rights) end before do stub_warden login_as @user end it 'should login' do AuthController.any_instance.stubs(:new_token).returns('12345') post :authenticate, :username => 'john', :password => 'password' JSON.parse(response.body)['token'].should == '12345' end it 'should deny login' do AuthController.any_instance.stubs(:new_token).returns(nil) post :authenticate, :username => 'john', :password => 'any-other-password' response.status.should == '403 Forbidden'.to_i end ... end
  14. authentication controller. describe AuthController do before :all { @user =

    Factory(:user_with_rights) } after :all { @user.destroy } before do stub_warden login_as @user end it 'should login' do AuthController.any_instance.stubs(:new_token).returns('12345') post :authenticate, :username => 'john', :password => 'password' JSON.parse(response.body)['token'].should == '12345' end it 'should deny login' do AuthController.any_instance.stubs(:new_token).returns(nil) post :authenticate, :username => 'john', :password => 'any-other-password' response.status.should == '403 Forbidden'.to_i end ... end
  15. avoid the database (as much as you can) http://blogs.the451group.com/information_management/files/2013/01/33148971.jpg

  16. model validation. FactoryGirl.define do factory :account do email 'example@example.com' end

    end class Account < ActiveRecord::Base ... validates_uniqueness_of :email, :message =>"Email already taken" ... end it 'should fail validation if the email is not unique' do account1 = Factory.create(:account) lambda { account2 = Factory.create(:account) }.should raise_error end
  17. model validation. FactoryGirl.define do factory :account do email 'example@example.com' end

    end class Account < ActiveRecord::Base ... validates_uniqueness_of :email, :message =>"Email already taken" ... end it 'should fail validation if the email is not unique' do Factory.create(:account) Factory.build(:account).should_not be_valid end
  18. don’t mock me. let (:phone) { Factory.create(:phone) } it 'should

    update the phone record' do phone.number = '123-4567' post, :update, :phone => phone.attributes response.should be_success phone.reload.number.should == '123-4567' end
  19. it’s okay to fake it. let (:phone) { Phone.new(:number =>

    '111-1111') } it 'should update the phone record' do Phone.expects(:find).returns(phone) phone.expects(:update_attributes).with do |params| params[:number].should == '123-4567' end.returns(true) post, :update, :phone => {:number => '123-4567') response.should be_success response.should render_template(:phone) end
  20. too much data. require 'spec_helper' describe GolfBallController ... it 'should

    fetch the first page' do 30.times do { Factory.create(:golf_ball) } get :index // default page_size = 20 response.should render_template('golf_balls/index') end ... end
  21. be frugal. require 'spec_helper' describe GolfBallController ... it 'should fetch

    the first page' do 3.times do { Factory.create(:golf_ball) } get :index, :page_size => 2 response.should render_template('golf_balls/index') end ... end
  22. other ideas. avoid loading rails defer garbage collection ** jasmine

    over cucumber unit over integration tests ** https://makandracards.com/makandra/950-speed-up-rspec-by-deferring-garbage-collection
  23. trust no one. don’t be fooled by local maxima http://cache.wealthinformatics.com/wp-content/uploads/2012/02/Whywontwequit.jpg

  24. Boy Scout Rule Always leave code (tests) cleaner than when

    you found it. http://www.goldenspread.org/Images/BoyScouts.jpg
  25. thank you. Avinash Chugh (avinashc@thoughtworks.com)