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.

D79fc498d7a5b2ce12180890247476f0?s=128

Jon Rowe

July 01, 2012
Tweet

Transcript

  1. 3.

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

    speed up your existing legacy tests. Sunday, 1 July 12
  2. 8.

    WHY FAST? We know this right? Shorten the feedback cycle

    Focus Actually write tests Sunday, 1 July 12
  3. 9.

    WHY FAST? We know this right? Shorten the feedback cycle

    Focus Actually write tests “Feel Awesome”@kytrinyx Sunday, 1 July 12
  4. 13.

    SAD TRUTH No test is faster than no tests F5DD

    Laziness is easy Sunday, 1 July 12
  5. 16.
  6. 17.

    SO WHY SLOW? “Your code makes it slow” Your tests

    make it slow And… Sunday, 1 July 12
  7. 19.

    FACT Rails is what makes your tests slow But that’s

    not Rails’ fault Sunday, 1 July 12
  8. 20.

    FACT Rails is what makes your tests slow But that’s

    not *all* Rails’ fault Sunday, 1 July 12
  9. 32.

    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
  10. 33.

    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
  11. 34.

    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
  12. 44.

    THE TESTS Unit test Skip filters Focus on your code

    Let Rails work Sunday, 1 July 12
  13. 45.

    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
  14. 46.

    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
  15. 48.

    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
  16. 49.

    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
  17. 50.

    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
  18. 57.

    MODELS So not much improvement DB calls? How can we

    make these faster? Sunday, 1 July 12
  19. 64.

    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
  20. 71.
  21. 72.

    BE SENSIBLE Test when it makes sense No hard and

    fast rules Consider the value Sunday, 1 July 12
  22. 80.

    SUMMARY Require what you need Unit test your units Abstract

    away Integration/acceptance test framework Sunday, 1 July 12
  23. 81.

    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
  24. 82.

    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