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

Practical Faster Testing (With Rails)

Practical Faster Testing (With Rails)

From the Scottish Ruby Conference Fringe event 2012.

A short talk with some tips and advice on how to get faster tests with Rails.

Jon Rowe

July 01, 2012
Tweet

More Decks by Jon Rowe

Other Decks in Programming

Transcript

  1. DISCLAIMER I’m not going to offer tips on how to

    speed up your existing legacy tests. Sunday, 1 July 12
  2. WHY FAST? We know this right? Shorten the feedback cycle

    Focus Actually write tests Sunday, 1 July 12
  3. WHY FAST? We know this right? Shorten the feedback cycle

    Focus Actually write tests “Feel Awesome”@kytrinyx Sunday, 1 July 12
  4. SAD TRUTH No test is faster than no tests F5DD

    Laziness is easy Sunday, 1 July 12
  5. SO WHY SLOW? “Your code makes it slow” Your tests

    make it slow And… Sunday, 1 July 12
  6. FACT Rails is what makes your tests slow But that’s

    not Rails’ fault Sunday, 1 July 12
  7. FACT Rails is what makes your tests slow But that’s

    not *all* Rails’ fault Sunday, 1 July 12
  8. class SensibleController < ApplicationController def index @objects = Record.all end

    def new @object = Record.new end def create Record.create params[:record] redirect_to index_path end def edit @record = Record.find(params[:id]) end def update Record.find(params[:id]).update_attributes params[:record] redirect_to index_path end end Sunday, 1 July 12
  9. class SensibleController < ApplicationController def create Record.create! params[:record] redirect_to index_path

    rescue @record = Record.new params[:record] render :new end def edit @record = Record.find(params[:id]) rescue NotFound redirect_to index_path end def update Record.find(params[:id]).update_attributes params[:record] redirect_to index_path rescue Validations @record = Record.new params[:record] render :edit rescue NotFound redirect_to index_path end end Sunday, 1 July 12
  10. class UberDeathController def index @bugs = if params[:q].blank? && params[:c].blank?

    && params[:m].blank? && params[:order].bla Bug.by_gnar_factor.paginate :per_page => @per_page, :page => params[:page] elsif params[:q].blank? && !params[:c].blank? && params[:m].blank? && params[:order] Bug.for_section(params[:c]).by_gnar_factor.paginate :per_page => @per_page, :page elsif params[:c].blank? && !params[:q].blank? && params[:m].blank? && params[:order] Bug.search_for(params[:q]).by_gnar_factor.paginate :per_page => @per_page, :page = elsif !params[:c].blank? && !params[:q].blank? && params[:m].blank? && params[:order Bug.search_for(params[:q]).by_gnar_factor.for_section(params[:c]).paginate :per_pa elsif params[:c].blank? && params[:q].blank? && !params[:m].blank? && params[:order] Bug.master_bugs.by_gnar_factor.paginate :per_page => @per_page, :page => params[:p elsif !params[:c].blank? && params[:q].blank? && !params[:m].blank? && params[:order Bug.master_bugs.by_gnar_factor.for_section(params[:c]).paginate :per_page => @per_ elsif params[:c].blank? && !params[:q].blank? && !params[:m].blank? && params[:order Bug.master_bugs.by_gnar_factor.search_for(params[:q]).paginate :per_page => @per_p elsif !params[:c].blank? && !params[:q].blank? && !params[:m].blank? && params[:orde Bug.master_bugs.by_gnar_factor.search_for(params[:q]).for_section(params[:c]).pagi end end end STILL DONT TEST? Sunday, 1 July 12
  11. THE TESTS Unit test Skip filters Focus on your code

    Let Rails work Sunday, 1 July 12
  12. INTEGRATION require 'spec_helper' describe ExampleWithModelController do describe 'post :create' do

    subject { post :create } it "creates a model" do expect { subject }.to change(RandomModel,:count).by(1) end it "redirects away" do subject.should redirect_to '/' end end end Sunday, 1 July 12
  13. INTEGRATION require 'spec_helper' describe ExampleWithModelController do describe 'post :create' do

    before { RandomModel.stub(:create) } subject { post :create } it "creates a RandomModel" do RandomModel.should_receive(:create) subject end it "redirects away" do subject.should redirect_to '/' end end end Sunday, 1 July 12
  14. class RandomModel; end describe ExampleWithModelController do describe '#create' do let(:controller)

    { described_class.new } before do controller.request = Struct.new(:parameters).new controller.stub(:redirect_to) end subject { controller.create } it "creates a RandomModel" do RandomModel.should_receive(:create) subject end it "redirects to away" do controller.should_receive(:redirect_to).with('/') subject end end end Sunday, 1 July 12
  15. RESULTS (x100) ============================ unit ============================ 0.000000 0.000000 1.140000 ( 1.149252)

    ============================ integration ============================ 0.000000 0.010000 2.510000 ( 2.498981) (stubbed) 0.000000 0.000000 3.070000 ( 3.175934) (full stack) Sunday, 1 July 12
  16. RESULTS (x1000) ============================ unit x1000 ============================ 0.000000 0.020000 3.060000 (

    3.051226) ============================ integration x1000 ============================ 0.010000 0.020000 8.380000 ( 8.382151) (stubbed) 0.010000 0.020000 13.160000 ( 15.175460) (full stack) Sunday, 1 July 12
  17. MODELS So not much improvement DB calls? How can we

    make these faster? Sunday, 1 July 12
  18. class ChangeStock def initialize(item) @item = item end def delta

    quantity - @item.quantity end def to(quantity) if quantity > @item.quantity @item.fee_generator.charge_increase delta end @item.set_quantity quantity @item.save! end end Sunday, 1 July 12
  19. BE SENSIBLE Test when it makes sense No hard and

    fast rules Consider the value Sunday, 1 July 12
  20. SUMMARY Require what you need Unit test your units Abstract

    away Integration/acceptance test framework Sunday, 1 July 12
  21. SUMMARY Require what you need Unit test your units Abstract

    away Integration/acceptance test framework Don’t boot rails unless needed Sunday, 1 July 12
  22. SUMMARY Require what you need Unit test your units Abstract

    away Integration/acceptance test framework Don’t boot rails unless needed Be sensible! Sunday, 1 July 12