SlideShare ist ein Scribd-Unternehmen logo
1 von 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”!

Weitere ähnliche Inhalte

Was ist angesagt?

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
 

Was ist angesagt? (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
 

Ähnlich wie 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
 

Ähnlich wie 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
 

Mehr von 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
 

Mehr von 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
 

Kürzlich hochgeladen

Unraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfUnraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfAlex Barbosa Coqueiro
 
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks..."LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...Fwdays
 
Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 3652toLead Limited
 
Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Manik S Magar
 
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Mark Simos
 
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdfHyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdfPrecisely
 
"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr BaganFwdays
 
Search Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdfSearch Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdfRankYa
 
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxMerck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxLoriGlavin3
 
Artificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptxArtificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptxhariprasad279825
 
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024BookNet Canada
 
How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.Curtis Poe
 
From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .Alan Dix
 
Advanced Computer Architecture – An Introduction
Advanced Computer Architecture – An IntroductionAdvanced Computer Architecture – An Introduction
Advanced Computer Architecture – An IntroductionDilum Bandara
 
"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii SoldatenkoFwdays
 
Human Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsHuman Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsMark Billinghurst
 
DevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenDevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenHervé Boutemy
 
WordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your BrandWordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your Brandgvaughan
 
TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc
 
The Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsThe Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsPixlogix Infotech
 

Kürzlich hochgeladen (20)

Unraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfUnraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdf
 
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks..."LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
 
Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365
 
Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!
 
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
 
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdfHyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
 
"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan
 
Search Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdfSearch Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdf
 
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxMerck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
 
Artificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptxArtificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptx
 
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
 
How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.
 
From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .
 
Advanced Computer Architecture – An Introduction
Advanced Computer Architecture – An IntroductionAdvanced Computer Architecture – An Introduction
Advanced Computer Architecture – An Introduction
 
"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko
 
Human Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsHuman Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR Systems
 
DevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenDevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache Maven
 
WordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your BrandWordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your Brand
 
TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
 
The Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsThe Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and Cons
 

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”!

Hinweis der Redaktion

  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