Upgrade to Pro — share decks privately, control downloads, hide ads and more …

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.

Avinash Chugh

March 15, 2013
Tweet

More Decks by Avinash Chugh

Other Decks in Programming

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. 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
  7. 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
  8. 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
  9. 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
  10. model validation. FactoryGirl.define do factory :account do email '[email protected]' 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
  11. model validation. FactoryGirl.define do factory :account do email '[email protected]' 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
  12. 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
  13. 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
  14. 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
  15. 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
  16. 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
  17. Boy Scout Rule Always leave code (tests) cleaner than when

    you found it. http://www.goldenspread.org/Images/BoyScouts.jpg