SlideShare uma empresa Scribd logo
1 de 46
Speedy TDD with Rails
Reclaiming your feedback loop (the wrong way)




     Creative Commons Attribution-Noncommercial-Share Alike
                                                                   Ash Moran
     2.0 UK: England & Wales License                          PatchSpace Ltd
ier
Speedy TDD with Rails
Reclaiming your feedback loop (the wrong way)




     Creative Commons Attribution-Noncommercial-Share Alike
                                                                   Ash Moran
     2.0 UK: England & Wales License                          PatchSpace Ltd
What say Google about tests?
JavaScript
Nothing unusual here
Clojure
Seems pretty uneventful too
Scala
Equally unexciting
Python
Testing is pretty boring really
Java
You’re probably ok as long as you speak German
C#
More concerned with recruitment than code
Fortran
You’re on your own
Django
Since, in fairness, we’re testing web apps here
Rails
You can hear their pained cries for help
Why does test speed matter?
Red




        Refactor                Green




The TDD loop
This constrains how fast you can learn whether
your code implements the specification
TDD orders of magnitude
0.01s
  Full-app validation on every run
0.1s
  Continuous development flow
1s
  Interrupted development flow
10s
  Check Twitter more than you check your app
What is the current situation?
Rails: one test
One RSpec example
RSpec 2.8.0 on MRI Ruby 1.9.3
Rails: 16 tests
Booting Rails is the constraint
What can we do?
Attack vector 1:
The Ruby Runtime
Upgrade from Ruby 1.9.2
The `require` method is much faster in 1.9.3
But… Heroku currently only offers 1.9.2
Switch to 1.8.7


 This was seriously proposed to me on the rspec-users
 list
 Baby + bathwater?
Attack vector 2:
Pre-loading and forking Rails
Spin

https://github.com/jstorimer/spin
Start the server (loads Rails): spin serve
Run tests
  spin push test/unit/product_test.rb
  spin push a_test.rb b_test.rb …
No changes to the app whatsoever
Internally does some jiggery-pokery for RSpec
Guard::Spin

guard 'spin' do
 watch(%r{^spec/.+_spec.rb})
 watch(%r{^app/(.+).rb})                   { |m| "spec/#{m[1]}_spec.rb" }
 watch(%r{^app/(.+).haml})                   { |m| "spec/#{m[1]}.haml_spec.rb" }
 watch(%r{^lib/(.+).rb})                 { |m| "spec/lib/#{m[1]}_spec.rb" }
 watch(%r{^app/controllers/(.+)_(controller).rb}) { |m|
   [
     "spec/routing/#{m[1]}_routing_spec.rb",
     "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb",
     "spec/requests/#{m[1]}_spec.rb"
   ]
 }
end
Guard::Spin
Faster, but not an order of magnitude faster
Outcome: only worth it if it causes no problems
Spork

https://github.com/sporkrb/spork
Requires changing spec_helper.rb
Uses enough metaprogramming monkey-patching of
Rails to summon a Greater Uncle Bob Daemon
  https://github.com/sporkrb/spork/blob/master/lib/
  spork/app_framework/rails.rb#L43-80
Spork monkey-patching
def preload_rails
 if deprecated_version && (not /^3/.match(deprecated_version))
   puts "This version of spork only supports Rails 3.0. To use spork with rails 2.3.x, downgrade to spork 0.8.x."
   exit 1
 end
 require application_file
 ::Rails.application
 ::Rails::Engine.class_eval do
   def eager_load!
    # turn off eager_loading, all together
   end
 end
 # Spork.trap_method(::AbstractController::Helpers::ClassMethods, :helper)
 Spork.trap_method(::ActiveModel::Observing::ClassMethods, :instantiate_observers)
 Spork.each_run { ActiveRecord::Base.establish_connection rescue nil } if Object.const_defined?(:ActiveRecord)

 …
Spork monkey-patching
…

AbstractController::Helpers::ClassMethods.module_eval do
 def helper(*args, &block)
  ([args].flatten - [:all]).each do |arg|
    next unless arg.is_a?(String)
    filename = arg + "_helper"
    unless ::ActiveSupport::Dependencies.search_for_file(filename)
     # this error message must raise in the format such that LoadError#path returns the filename
     raise LoadError.new("Missing helper file helpers/%s.rb" % filename)
    end
  end

    Spork.each_run(false) do
     modules_for_helpers(args).each do |mod|
      add_template_helper(mod)
     end

    _helpers.module_eval(&block) if block_given?
  end
 end
end
Forking Rails?
 Only saves part of the time
 Introduces potential problems
   Reloading the pre-fork
   Hacks to make it work
 Can introduce many subtle bugs
 Doesn’t address the real problem: depending on Rails
Attack vector 3:
Hijack code reloading for
browser integration tests
Code reloading

Used in the development environment
Called cache_classes
  This is a lie! Ruby does not have real code reloading
  like Erlang
Can be used to speed up browser integration tests
  Called “acceptance” here, which may not be true
Guard::Rails

# Running with `daemon: true` because I can't figure out how to turn off enough Rails logging
guard "rails", environment: "acceptance", server: :thin, port: 3100, daemon: true do
 watch("Gemfile.lock")
 watch(%r{^(config|lib)/.*})
end

guard "rspec", spec_paths: %w[ spec/acceptance ], cli: "--color --format Fuubar" do
 watch(%r{^spec/acceptance/.+_spec.rb$})
end
environments/acceptance.rb
  MyApp::Application.configure do
   config.cache_classes = false
   config.consider_all_requests_local = true
   config.active_support.deprecation = :log
   config.assets.compress = false
   config.action_mailer.default_url_options = { :host => 'localhost:3000' }
   config.action_mailer.delivery_method = :smtp
   config.action_mailer.smtp_settings = {
     :address => "localhost", :port => 1025, :enable_starttls_auto => false
   }

   # Disable logging for now (too much noise in Guard)
   # I couldn't figure out how to make it log so running this as a daemon instead
   # config.logger = nil
   # config.action_controller.logger = nil
   # config.action_view.logger = nil
  end

  Mongoid.configure do |config|
   config.logger = nil
  end
capybara-webkit tests
Feedback time comparable to controller tests
Code reloading summary

Speeds up start time of browser tests considerably
Tests must be written to work cross-process
Fewer issues than Spin/Spork (lesser of two evils)
No help at all speeding up controller tests
Still doesn’t address the real problem
Attack vector 4:
Split the tests by dependency
Example: Mongoid
  require 'spec_helper'
  require 'spec/environments/mongoid'

  require_unless_rails_loaded 'app/models/question'
  require_unless_rails_loaded 'app/models/user'

  require 'spec/support/blueprints/question'

  describe Question do
   describe "#populate" do
    let(:source_question) {
      Question.make(value: "Submetric 1a Q1", comment: "Submetric 1a A1")
    }
    let(:target_question) {
      Question.make(value: "this does not get overwritten", comment: "this gets overwritten")
    }

    before(:each) do
     source_question.populate(target_question)
    end

    subject { target_question }

    its(:value) { should be == "this does not get overwritten" }
    its(:comment) { should be == "Submetric 1a A1" }
   end
  end
spec/environments/mongoid
    require_relative 'common'

    # Gem dependencies
    require 'mongoid'

    if !rails_loaded?
      ENV["RACK_ENV"] ||= "test" # Hack to use the Mongoid.load!
      Mongoid.load!("config/mongoid.yml")
      Mongoid.configure do |config|
        config.logger = nil
      end
    end

    RSpec.configure do |config|
     config.before(:each) do
      Mongoid::IdentityMap.clear
     end
    end
spec/environments/common


       def require_unless_rails_loaded(file)
        require(file) unless rails_loaded?
       end




      This may be paranoia
spec_helper.rb


       def rails_loaded?
        Object.const_defined?(:MyApp) &&
         MyApp.const_defined?(:Application)
       end
Guardfile (multiple guards)

  guard "rspec", spec_paths: %w[ spec/controllers ], cli: "--color --format Fuubar" do
   watch('spec/environments/rails.rb')     { "spec/controllers" }

   watch(%r{^spec/controllers/.+_spec.rb$})
   watch(%r{^app/controllers/(.+).rb$})   { |m| "spec/#{m[1]}_spec.rb" }
  end

  guard "rspec", spec_paths: %w[ spec/models ], cli: "--color --format Fuubar" do
   watch('spec/spec_helper.rb')      { "spec/models" }
   watch('spec/environments/mongoid.rb') { "spec/models" }
   watch(%r{^spec/support/(.+).rb$}) { "spec/models" }

   watch(%r{^spec/models/.+_spec.rb$})
   watch(%r{^app/models/(.+).rb$})  { |m| "spec/#{m[1]}_spec.rb" }
   watch(%r{^app/models/concerns.rb$}) { |m| "spec/models" }
  end
Running in Guard
Mongoid tests now running ~1s not ~10s
Not brilliant, but an order of magnitude change
Concluding thoughts
How much does this help?

Bypassing the Rails boot process can increase
feedback speed by an order of magnitude
Without changing your code, you can turn a nightmare
into a bad dream
The size of the gains depend on how many
dependencies you have left
Is this the right way?


 No.
 Tune in next month for “Speedy TDD in Rails (the
 righter way”!

Mais conteúdo relacionado

Mais procurados

Building a Reactive System with Akka - Workshop @ O'Reilly SAConf NYC
Building a Reactive System with Akka - Workshop @ O'Reilly SAConf NYCBuilding a Reactive System with Akka - Workshop @ O'Reilly SAConf NYC
Building a Reactive System with Akka - Workshop @ O'Reilly SAConf NYCKonrad Malawski
 
Frontend Performance: Expert to Crazy Person
Frontend Performance: Expert to Crazy PersonFrontend Performance: Expert to Crazy Person
Frontend Performance: Expert to Crazy PersonPhilip Tellis
 
Patterns and practices for building resilient serverless applications
Patterns and practices for building resilient serverless applicationsPatterns and practices for building resilient serverless applications
Patterns and practices for building resilient serverless applicationsYan Cui
 
The MetaCPAN VM for Dummies Part One (Installation)
The MetaCPAN VM for Dummies Part One (Installation)The MetaCPAN VM for Dummies Part One (Installation)
The MetaCPAN VM for Dummies Part One (Installation)Olaf Alders
 
What's new and great in Rails 3 - Matt Gauger - Milwaukee Ruby Users Group De...
What's new and great in Rails 3 - Matt Gauger - Milwaukee Ruby Users Group De...What's new and great in Rails 3 - Matt Gauger - Milwaukee Ruby Users Group De...
What's new and great in Rails 3 - Matt Gauger - Milwaukee Ruby Users Group De...Matt Gauger
 
Patterns and practices for building resilient serverless applications.pdf
Patterns and practices for building resilient serverless applications.pdfPatterns and practices for building resilient serverless applications.pdf
Patterns and practices for building resilient serverless applications.pdfYan Cui
 
Swagger AEM - An OpenAPI Specification for AEM
Swagger AEM - An OpenAPI Specification for AEMSwagger AEM - An OpenAPI Specification for AEM
Swagger AEM - An OpenAPI Specification for AEMCliffano Subagio
 
Matt Gauger - Lamp vs. the world - MKE PHP Users Group - December 14, 2010
Matt Gauger - Lamp vs. the world - MKE PHP Users Group - December 14, 2010 Matt Gauger - Lamp vs. the world - MKE PHP Users Group - December 14, 2010
Matt Gauger - Lamp vs. the world - MKE PHP Users Group - December 14, 2010 Matt Gauger
 
Ruby off Rails---rack, sinatra and sequel
Ruby off Rails---rack, sinatra and sequelRuby off Rails---rack, sinatra and sequel
Ruby off Rails---rack, sinatra and sequelJiang Wu
 
Seven perilous pitfalls to avoid with Java | DevNation Tech Talk
Seven perilous pitfalls to avoid with Java | DevNation Tech TalkSeven perilous pitfalls to avoid with Java | DevNation Tech Talk
Seven perilous pitfalls to avoid with Java | DevNation Tech TalkRed Hat Developers
 
Using PHP Functions! (Not those functions, Google Cloud Functions)
Using PHP Functions! (Not those functions, Google Cloud Functions)Using PHP Functions! (Not those functions, Google Cloud Functions)
Using PHP Functions! (Not those functions, Google Cloud Functions)Chris Tankersley
 
Your first sinatra app
Your first sinatra appYour first sinatra app
Your first sinatra appRubyc Slides
 
Killer Docker Workflows for Development
Killer Docker Workflows for DevelopmentKiller Docker Workflows for Development
Killer Docker Workflows for DevelopmentChris Tankersley
 
Docker for Developers - PHP Detroit 2018
Docker for Developers - PHP Detroit 2018Docker for Developers - PHP Detroit 2018
Docker for Developers - PHP Detroit 2018Chris Tankersley
 
Need for Async: Hot pursuit for scalable applications
Need for Async: Hot pursuit for scalable applicationsNeed for Async: Hot pursuit for scalable applications
Need for Async: Hot pursuit for scalable applicationsKonrad Malawski
 
Frontend Performance: Beginner to Expert to Crazy Person
Frontend Performance: Beginner to Expert to Crazy PersonFrontend Performance: Beginner to Expert to Crazy Person
Frontend Performance: Beginner to Expert to Crazy PersonPhilip Tellis
 
10 Laravel packages everyone should know
10 Laravel packages everyone should know10 Laravel packages everyone should know
10 Laravel packages everyone should knowPovilas Korop
 

Mais procurados (20)

Building a Reactive System with Akka - Workshop @ O'Reilly SAConf NYC
Building a Reactive System with Akka - Workshop @ O'Reilly SAConf NYCBuilding a Reactive System with Akka - Workshop @ O'Reilly SAConf NYC
Building a Reactive System with Akka - Workshop @ O'Reilly SAConf NYC
 
Async await...oh wait!
Async await...oh wait!Async await...oh wait!
Async await...oh wait!
 
Frontend Performance: Expert to Crazy Person
Frontend Performance: Expert to Crazy PersonFrontend Performance: Expert to Crazy Person
Frontend Performance: Expert to Crazy Person
 
Patterns and practices for building resilient serverless applications
Patterns and practices for building resilient serverless applicationsPatterns and practices for building resilient serverless applications
Patterns and practices for building resilient serverless applications
 
The MetaCPAN VM for Dummies Part One (Installation)
The MetaCPAN VM for Dummies Part One (Installation)The MetaCPAN VM for Dummies Part One (Installation)
The MetaCPAN VM for Dummies Part One (Installation)
 
What's new and great in Rails 3 - Matt Gauger - Milwaukee Ruby Users Group De...
What's new and great in Rails 3 - Matt Gauger - Milwaukee Ruby Users Group De...What's new and great in Rails 3 - Matt Gauger - Milwaukee Ruby Users Group De...
What's new and great in Rails 3 - Matt Gauger - Milwaukee Ruby Users Group De...
 
Patterns and practices for building resilient serverless applications.pdf
Patterns and practices for building resilient serverless applications.pdfPatterns and practices for building resilient serverless applications.pdf
Patterns and practices for building resilient serverless applications.pdf
 
Swagger AEM - An OpenAPI Specification for AEM
Swagger AEM - An OpenAPI Specification for AEMSwagger AEM - An OpenAPI Specification for AEM
Swagger AEM - An OpenAPI Specification for AEM
 
Matt Gauger - Lamp vs. the world - MKE PHP Users Group - December 14, 2010
Matt Gauger - Lamp vs. the world - MKE PHP Users Group - December 14, 2010 Matt Gauger - Lamp vs. the world - MKE PHP Users Group - December 14, 2010
Matt Gauger - Lamp vs. the world - MKE PHP Users Group - December 14, 2010
 
Ruby off Rails---rack, sinatra and sequel
Ruby off Rails---rack, sinatra and sequelRuby off Rails---rack, sinatra and sequel
Ruby off Rails---rack, sinatra and sequel
 
Seven perilous pitfalls to avoid with Java | DevNation Tech Talk
Seven perilous pitfalls to avoid with Java | DevNation Tech TalkSeven perilous pitfalls to avoid with Java | DevNation Tech Talk
Seven perilous pitfalls to avoid with Java | DevNation Tech Talk
 
Using PHP Functions! (Not those functions, Google Cloud Functions)
Using PHP Functions! (Not those functions, Google Cloud Functions)Using PHP Functions! (Not those functions, Google Cloud Functions)
Using PHP Functions! (Not those functions, Google Cloud Functions)
 
Plack at YAPC::NA 2010
Plack at YAPC::NA 2010Plack at YAPC::NA 2010
Plack at YAPC::NA 2010
 
Your first sinatra app
Your first sinatra appYour first sinatra app
Your first sinatra app
 
Killer Docker Workflows for Development
Killer Docker Workflows for DevelopmentKiller Docker Workflows for Development
Killer Docker Workflows for Development
 
Beyond AEM Curl Commands
Beyond AEM Curl CommandsBeyond AEM Curl Commands
Beyond AEM Curl Commands
 
Docker for Developers - PHP Detroit 2018
Docker for Developers - PHP Detroit 2018Docker for Developers - PHP Detroit 2018
Docker for Developers - PHP Detroit 2018
 
Need for Async: Hot pursuit for scalable applications
Need for Async: Hot pursuit for scalable applicationsNeed for Async: Hot pursuit for scalable applications
Need for Async: Hot pursuit for scalable applications
 
Frontend Performance: Beginner to Expert to Crazy Person
Frontend Performance: Beginner to Expert to Crazy PersonFrontend Performance: Beginner to Expert to Crazy Person
Frontend Performance: Beginner to Expert to Crazy Person
 
10 Laravel packages everyone should know
10 Laravel packages everyone should know10 Laravel packages everyone should know
10 Laravel packages everyone should know
 

Semelhante a Speedy TDD with Rails

Connecting the Worlds of Java and Ruby with JRuby
Connecting the Worlds of Java and Ruby with JRubyConnecting the Worlds of Java and Ruby with JRuby
Connecting the Worlds of Java and Ruby with JRubyNick Sieger
 
Building web framework with Rack
Building web framework with RackBuilding web framework with Rack
Building web framework with Racksickill
 
TorqueBox - Ruby Hoedown 2011
TorqueBox - Ruby Hoedown 2011TorqueBox - Ruby Hoedown 2011
TorqueBox - Ruby Hoedown 2011Lance Ball
 
[Srijan Wednesday Webinar] Rails 5: What's in It for Me?
[Srijan Wednesday Webinar] Rails 5: What's in It for Me?[Srijan Wednesday Webinar] Rails 5: What's in It for Me?
[Srijan Wednesday Webinar] Rails 5: What's in It for Me?Srijan Technologies
 
Torquebox OSCON Java 2011
Torquebox OSCON Java 2011Torquebox OSCON Java 2011
Torquebox OSCON Java 2011tobiascrawley
 
.NET Architects Day - DNAD 2011
.NET Architects Day - DNAD 2011.NET Architects Day - DNAD 2011
.NET Architects Day - DNAD 2011Fabio Akita
 
09 - Fábio Akita - Além do rails
09 - Fábio Akita - Além do rails09 - Fábio Akita - Além do rails
09 - Fábio Akita - Além do railsDNAD
 
Ruby on Rails survival guide of an aged Java developer
Ruby on Rails survival guide of an aged Java developerRuby on Rails survival guide of an aged Java developer
Ruby on Rails survival guide of an aged Java developergicappa
 
Infrastructureascode slideshare-160331143725
Infrastructureascode slideshare-160331143725Infrastructureascode slideshare-160331143725
Infrastructureascode slideshare-160331143725miguel dominguez
 
Infrastructureascode slideshare-160331143725
Infrastructureascode slideshare-160331143725Infrastructureascode slideshare-160331143725
Infrastructureascode slideshare-160331143725MortazaJohari
 
Infrastructure as code: running microservices on AWS using Docker, Terraform,...
Infrastructure as code: running microservices on AWS using Docker, Terraform,...Infrastructure as code: running microservices on AWS using Docker, Terraform,...
Infrastructure as code: running microservices on AWS using Docker, Terraform,...Yevgeniy Brikman
 
Fisl - Deployment
Fisl - DeploymentFisl - Deployment
Fisl - DeploymentFabio Akita
 
Behavioural Testing Ruby/Rails Apps @ Scale - Rspec & Cucumber
       Behavioural Testing Ruby/Rails Apps @ Scale - Rspec & Cucumber       Behavioural Testing Ruby/Rails Apps @ Scale - Rspec & Cucumber
Behavioural Testing Ruby/Rails Apps @ Scale - Rspec & CucumberUdaya Kiran
 
Introduction to Rails - presented by Arman Ortega
Introduction to Rails - presented by Arman OrtegaIntroduction to Rails - presented by Arman Ortega
Introduction to Rails - presented by Arman Ortegaarman o
 
Get Going With RVM and Rails 3
Get Going With RVM and Rails 3Get Going With RVM and Rails 3
Get Going With RVM and Rails 3Karmen Blake
 

Semelhante a Speedy TDD with Rails (20)

Connecting the Worlds of Java and Ruby with JRuby
Connecting the Worlds of Java and Ruby with JRubyConnecting the Worlds of Java and Ruby with JRuby
Connecting the Worlds of Java and Ruby with JRuby
 
Intro to Rack
Intro to RackIntro to Rack
Intro to Rack
 
Building web framework with Rack
Building web framework with RackBuilding web framework with Rack
Building web framework with Rack
 
TorqueBox - Ruby Hoedown 2011
TorqueBox - Ruby Hoedown 2011TorqueBox - Ruby Hoedown 2011
TorqueBox - Ruby Hoedown 2011
 
RoR guide_p1
RoR guide_p1RoR guide_p1
RoR guide_p1
 
[Srijan Wednesday Webinar] Rails 5: What's in It for Me?
[Srijan Wednesday Webinar] Rails 5: What's in It for Me?[Srijan Wednesday Webinar] Rails 5: What's in It for Me?
[Srijan Wednesday Webinar] Rails 5: What's in It for Me?
 
Torquebox OSCON Java 2011
Torquebox OSCON Java 2011Torquebox OSCON Java 2011
Torquebox OSCON Java 2011
 
Rack
RackRack
Rack
 
.NET Architects Day - DNAD 2011
.NET Architects Day - DNAD 2011.NET Architects Day - DNAD 2011
.NET Architects Day - DNAD 2011
 
09 - Fábio Akita - Além do rails
09 - Fábio Akita - Além do rails09 - Fábio Akita - Além do rails
09 - Fábio Akita - Além do rails
 
Ruby on Rails survival guide of an aged Java developer
Ruby on Rails survival guide of an aged Java developerRuby on Rails survival guide of an aged Java developer
Ruby on Rails survival guide of an aged Java developer
 
Infrastructureascode slideshare-160331143725
Infrastructureascode slideshare-160331143725Infrastructureascode slideshare-160331143725
Infrastructureascode slideshare-160331143725
 
Infrastructureascode slideshare-160331143725
Infrastructureascode slideshare-160331143725Infrastructureascode slideshare-160331143725
Infrastructureascode slideshare-160331143725
 
Infrastructure as code: running microservices on AWS using Docker, Terraform,...
Infrastructure as code: running microservices on AWS using Docker, Terraform,...Infrastructure as code: running microservices on AWS using Docker, Terraform,...
Infrastructure as code: running microservices on AWS using Docker, Terraform,...
 
TorqueBox
TorqueBoxTorqueBox
TorqueBox
 
Fisl - Deployment
Fisl - DeploymentFisl - Deployment
Fisl - Deployment
 
Behavioural Testing Ruby/Rails Apps @ Scale - Rspec & Cucumber
       Behavioural Testing Ruby/Rails Apps @ Scale - Rspec & Cucumber       Behavioural Testing Ruby/Rails Apps @ Scale - Rspec & Cucumber
Behavioural Testing Ruby/Rails Apps @ Scale - Rspec & Cucumber
 
Introduction to Rails - presented by Arman Ortega
Introduction to Rails - presented by Arman OrtegaIntroduction to Rails - presented by Arman Ortega
Introduction to Rails - presented by Arman Ortega
 
Get Going With RVM and Rails 3
Get Going With RVM and Rails 3Get Going With RVM and Rails 3
Get Going With RVM and Rails 3
 
rails.html
rails.htmlrails.html
rails.html
 

Mais de PatchSpace Ltd

Conflict in Complex Systems
Conflict in Complex SystemsConflict in Complex Systems
Conflict in Complex SystemsPatchSpace Ltd
 
Personal Kanban (lightning talk)
Personal Kanban (lightning talk)Personal Kanban (lightning talk)
Personal Kanban (lightning talk)PatchSpace Ltd
 
Parsing for Fun and Profit
Parsing for Fun and ProfitParsing for Fun and Profit
Parsing for Fun and ProfitPatchSpace Ltd
 
Why Won't My Car Start?
Why Won't My Car Start?Why Won't My Car Start?
Why Won't My Car Start?PatchSpace Ltd
 
ShRUG 5 - Scottish Ruby Conf edition
ShRUG 5  - Scottish Ruby Conf editionShRUG 5  - Scottish Ruby Conf edition
ShRUG 5 - Scottish Ruby Conf editionPatchSpace Ltd
 
Encouraging Agile Discipline
Encouraging Agile DisciplineEncouraging Agile Discipline
Encouraging Agile DisciplinePatchSpace Ltd
 
From Specification To Success
From Specification To SuccessFrom Specification To Success
From Specification To SuccessPatchSpace Ltd
 
Uses & Abuses of Mocks & Stubs
Uses & Abuses of Mocks & StubsUses & Abuses of Mocks & Stubs
Uses & Abuses of Mocks & StubsPatchSpace Ltd
 
NWRUG July 2009 - Darcs
NWRUG July 2009 - DarcsNWRUG July 2009 - Darcs
NWRUG July 2009 - DarcsPatchSpace Ltd
 
Elephants In The Meeting Room
Elephants In The Meeting RoomElephants In The Meeting Room
Elephants In The Meeting RoomPatchSpace Ltd
 

Mais de PatchSpace Ltd (10)

Conflict in Complex Systems
Conflict in Complex SystemsConflict in Complex Systems
Conflict in Complex Systems
 
Personal Kanban (lightning talk)
Personal Kanban (lightning talk)Personal Kanban (lightning talk)
Personal Kanban (lightning talk)
 
Parsing for Fun and Profit
Parsing for Fun and ProfitParsing for Fun and Profit
Parsing for Fun and Profit
 
Why Won't My Car Start?
Why Won't My Car Start?Why Won't My Car Start?
Why Won't My Car Start?
 
ShRUG 5 - Scottish Ruby Conf edition
ShRUG 5  - Scottish Ruby Conf editionShRUG 5  - Scottish Ruby Conf edition
ShRUG 5 - Scottish Ruby Conf edition
 
Encouraging Agile Discipline
Encouraging Agile DisciplineEncouraging Agile Discipline
Encouraging Agile Discipline
 
From Specification To Success
From Specification To SuccessFrom Specification To Success
From Specification To Success
 
Uses & Abuses of Mocks & Stubs
Uses & Abuses of Mocks & StubsUses & Abuses of Mocks & Stubs
Uses & Abuses of Mocks & Stubs
 
NWRUG July 2009 - Darcs
NWRUG July 2009 - DarcsNWRUG July 2009 - Darcs
NWRUG July 2009 - Darcs
 
Elephants In The Meeting Room
Elephants In The Meeting RoomElephants In The Meeting Room
Elephants In The Meeting Room
 

Último

Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101Paola De la Torre
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsEnterprise Knowledge
 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityPrincipled Technologies
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationMichael W. Hawkins
 
A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024Results
 
Top 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live StreamsTop 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live StreamsRoshan Dwivedi
 
Developing An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of BrazilDeveloping An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of BrazilV3cube
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdfhans926745
 
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure serviceWhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure servicePooja Nehwal
 
Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Enterprise Knowledge
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processorsdebabhi2
 
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfThe Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfEnterprise Knowledge
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsMaria Levchenko
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...Neo4j
 
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...Neo4j
 
Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024The Digital Insurer
 
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking MenDelhi Call girls
 
Unblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesUnblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesSinan KOZAK
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Servicegiselly40
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountPuma Security, LLC
 

Último (20)

Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI Solutions
 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivity
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day Presentation
 
A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024
 
Top 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live StreamsTop 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live Streams
 
Developing An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of BrazilDeveloping An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of Brazil
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf
 
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure serviceWhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
 
Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
 
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfThe Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed texts
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
 
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
 
Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024
 
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
 
Unblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesUnblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen Frames
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Service
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path Mount
 

Speedy TDD with Rails

  • 1. Speedy TDD with Rails Reclaiming your feedback loop (the wrong way) Creative Commons Attribution-Noncommercial-Share Alike Ash Moran 2.0 UK: England & Wales License PatchSpace Ltd
  • 2. ier Speedy TDD with Rails Reclaiming your feedback loop (the wrong way) Creative Commons Attribution-Noncommercial-Share Alike Ash Moran 2.0 UK: England & Wales License PatchSpace Ltd
  • 3. What say Google about tests?
  • 7. Python Testing is pretty boring really
  • 8. Java You’re probably ok as long as you speak German
  • 9. C# More concerned with recruitment than code
  • 11. Django Since, in fairness, we’re testing web apps here
  • 12. Rails You can hear their pained cries for help
  • 13. Why does test speed matter?
  • 14. Red Refactor Green The TDD loop This constrains how fast you can learn whether your code implements the specification
  • 15. TDD orders of magnitude 0.01s Full-app validation on every run 0.1s Continuous development flow 1s Interrupted development flow 10s Check Twitter more than you check your app
  • 16. What is the current situation?
  • 17. Rails: one test One RSpec example RSpec 2.8.0 on MRI Ruby 1.9.3
  • 18. Rails: 16 tests Booting Rails is the constraint
  • 19. What can we do?
  • 20. Attack vector 1: The Ruby Runtime
  • 21. Upgrade from Ruby 1.9.2 The `require` method is much faster in 1.9.3 But… Heroku currently only offers 1.9.2
  • 22. Switch to 1.8.7 This was seriously proposed to me on the rspec-users list Baby + bathwater?
  • 23. Attack vector 2: Pre-loading and forking Rails
  • 24. Spin https://github.com/jstorimer/spin Start the server (loads Rails): spin serve Run tests spin push test/unit/product_test.rb spin push a_test.rb b_test.rb … No changes to the app whatsoever Internally does some jiggery-pokery for RSpec
  • 25. Guard::Spin guard 'spin' do watch(%r{^spec/.+_spec.rb}) watch(%r{^app/(.+).rb}) { |m| "spec/#{m[1]}_spec.rb" } watch(%r{^app/(.+).haml}) { |m| "spec/#{m[1]}.haml_spec.rb" } watch(%r{^lib/(.+).rb}) { |m| "spec/lib/#{m[1]}_spec.rb" } watch(%r{^app/controllers/(.+)_(controller).rb}) { |m| [ "spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/requests/#{m[1]}_spec.rb" ] } end
  • 26. Guard::Spin Faster, but not an order of magnitude faster Outcome: only worth it if it causes no problems
  • 27. Spork https://github.com/sporkrb/spork Requires changing spec_helper.rb Uses enough metaprogramming monkey-patching of Rails to summon a Greater Uncle Bob Daemon https://github.com/sporkrb/spork/blob/master/lib/ spork/app_framework/rails.rb#L43-80
  • 28. Spork monkey-patching def preload_rails if deprecated_version && (not /^3/.match(deprecated_version)) puts "This version of spork only supports Rails 3.0. To use spork with rails 2.3.x, downgrade to spork 0.8.x." exit 1 end require application_file ::Rails.application ::Rails::Engine.class_eval do def eager_load! # turn off eager_loading, all together end end # Spork.trap_method(::AbstractController::Helpers::ClassMethods, :helper) Spork.trap_method(::ActiveModel::Observing::ClassMethods, :instantiate_observers) Spork.each_run { ActiveRecord::Base.establish_connection rescue nil } if Object.const_defined?(:ActiveRecord) …
  • 29. Spork monkey-patching … AbstractController::Helpers::ClassMethods.module_eval do def helper(*args, &block) ([args].flatten - [:all]).each do |arg| next unless arg.is_a?(String) filename = arg + "_helper" unless ::ActiveSupport::Dependencies.search_for_file(filename) # this error message must raise in the format such that LoadError#path returns the filename raise LoadError.new("Missing helper file helpers/%s.rb" % filename) end end Spork.each_run(false) do modules_for_helpers(args).each do |mod| add_template_helper(mod) end _helpers.module_eval(&block) if block_given? end end end
  • 30. Forking Rails? Only saves part of the time Introduces potential problems Reloading the pre-fork Hacks to make it work Can introduce many subtle bugs Doesn’t address the real problem: depending on Rails
  • 31. Attack vector 3: Hijack code reloading for browser integration tests
  • 32. Code reloading Used in the development environment Called cache_classes This is a lie! Ruby does not have real code reloading like Erlang Can be used to speed up browser integration tests Called “acceptance” here, which may not be true
  • 33. Guard::Rails # Running with `daemon: true` because I can't figure out how to turn off enough Rails logging guard "rails", environment: "acceptance", server: :thin, port: 3100, daemon: true do watch("Gemfile.lock") watch(%r{^(config|lib)/.*}) end guard "rspec", spec_paths: %w[ spec/acceptance ], cli: "--color --format Fuubar" do watch(%r{^spec/acceptance/.+_spec.rb$}) end
  • 34. environments/acceptance.rb MyApp::Application.configure do config.cache_classes = false config.consider_all_requests_local = true config.active_support.deprecation = :log config.assets.compress = false config.action_mailer.default_url_options = { :host => 'localhost:3000' } config.action_mailer.delivery_method = :smtp config.action_mailer.smtp_settings = { :address => "localhost", :port => 1025, :enable_starttls_auto => false } # Disable logging for now (too much noise in Guard) # I couldn't figure out how to make it log so running this as a daemon instead # config.logger = nil # config.action_controller.logger = nil # config.action_view.logger = nil end Mongoid.configure do |config| config.logger = nil end
  • 35. capybara-webkit tests Feedback time comparable to controller tests
  • 36. Code reloading summary Speeds up start time of browser tests considerably Tests must be written to work cross-process Fewer issues than Spin/Spork (lesser of two evils) No help at all speeding up controller tests Still doesn’t address the real problem
  • 37. Attack vector 4: Split the tests by dependency
  • 38. Example: Mongoid require 'spec_helper' require 'spec/environments/mongoid' require_unless_rails_loaded 'app/models/question' require_unless_rails_loaded 'app/models/user' require 'spec/support/blueprints/question' describe Question do describe "#populate" do let(:source_question) { Question.make(value: "Submetric 1a Q1", comment: "Submetric 1a A1") } let(:target_question) { Question.make(value: "this does not get overwritten", comment: "this gets overwritten") } before(:each) do source_question.populate(target_question) end subject { target_question } its(:value) { should be == "this does not get overwritten" } its(:comment) { should be == "Submetric 1a A1" } end end
  • 39. spec/environments/mongoid require_relative 'common' # Gem dependencies require 'mongoid' if !rails_loaded? ENV["RACK_ENV"] ||= "test" # Hack to use the Mongoid.load! Mongoid.load!("config/mongoid.yml") Mongoid.configure do |config| config.logger = nil end end RSpec.configure do |config| config.before(:each) do Mongoid::IdentityMap.clear end end
  • 40. spec/environments/common def require_unless_rails_loaded(file) require(file) unless rails_loaded? end This may be paranoia
  • 41. spec_helper.rb def rails_loaded? Object.const_defined?(:MyApp) && MyApp.const_defined?(:Application) end
  • 42. Guardfile (multiple guards) guard "rspec", spec_paths: %w[ spec/controllers ], cli: "--color --format Fuubar" do watch('spec/environments/rails.rb') { "spec/controllers" } watch(%r{^spec/controllers/.+_spec.rb$}) watch(%r{^app/controllers/(.+).rb$}) { |m| "spec/#{m[1]}_spec.rb" } end guard "rspec", spec_paths: %w[ spec/models ], cli: "--color --format Fuubar" do watch('spec/spec_helper.rb') { "spec/models" } watch('spec/environments/mongoid.rb') { "spec/models" } watch(%r{^spec/support/(.+).rb$}) { "spec/models" } watch(%r{^spec/models/.+_spec.rb$}) watch(%r{^app/models/(.+).rb$}) { |m| "spec/#{m[1]}_spec.rb" } watch(%r{^app/models/concerns.rb$}) { |m| "spec/models" } end
  • 43. Running in Guard Mongoid tests now running ~1s not ~10s Not brilliant, but an order of magnitude change
  • 45. How much does this help? Bypassing the Rails boot process can increase feedback speed by an order of magnitude Without changing your code, you can turn a nightmare into a bad dream The size of the gains depend on how many dependencies you have left
  • 46. Is this the right way? No. Tune in next month for “Speedy TDD in Rails (the righter way”!

Notas do Editor

  1. \n
  2. \n
  3. \n
  4. \n
  5. \n
  6. \n
  7. \n
  8. \n
  9. \n
  10. \n
  11. \n
  12. \n
  13. \n
  14. \n
  15. \n
  16. \n
  17. \n
  18. \n
  19. \n
  20. \n
  21. \n
  22. \n
  23. \n
  24. \n
  25. \n
  26. \n
  27. \n
  28. \n
  29. \n
  30. \n
  31. \n
  32. \n
  33. \n
  34. \n
  35. \n
  36. \n
  37. \n
  38. \n
  39. \n
  40. \n
  41. \n
  42. \n
  43. \n
  44. \n
  45. \n
  46. \n
  47. \n