smart | Webentwicklung
Alles rund um HTML5, PHP, WordPress & Co.

Ruby on Rails Tests mit Spork beschleunigen

27. Juni 2012
Stephan
Ruby on Rails Tests mit Spork beschleunigen

Wer seine Ruby on Rails Applikationen mit RSpec oder Cucumber testet, dem ist vielleicht aufgefallen, dass die Ausführung der Tests manchmal sehr viel Zeit benötigt.

Das Problem ist, dass jedes mal wenn die Tests gestartet werden, der komplette Ruby on Rails Stack neu geladen werden muss. Mit der Erweiterung (Gem) Spork gibt es jedoch ein Tool, um die Ausführung der Tests zu beschleunigen.

In diesem Artikel möchte ich euch zeigen, wie ihr Spork installiert und einrichtet.

Spork installieren

Um Spork zu installieren, fügt ihr in eure Gemfile-Datei einfach folgende Zeile Code innerhalb eures group :test-Blocks:

gem 'spork', '~> 0.9.2'

Anschließend ruft ihr in eurer Konsole bundle install auf, um Spork zu installieren.

Spork für RSpec einrichten

Als nächstes müssen wir unsere RSpec spec_helper.rb-Datei anpassen. Dazu rufen wir in unserer Konsole spork rspec--bootstrap auf.

Anschließend öffnen wir die spec_helper.rb-Datei. Hier sollten wir nun am Anfang der Datei den von Spork eingefügten Code sehen und darunter den alt bekannten spec_helper.rb-Code.

Als nächstes kopieren wir den alten Code in den Spork.prefork-Block, so dass unsere spec_helper.rb jetzt so aussehen sollte:

require 'rubygems'
require 'spork'

Spork.prefork do
    # Loading more in this block will cause your tests to run faster. However,
    # if you change any configuration or code from libraries loaded here, you'll
    # need to restart spork for it take effect.

    # This file is copied to spec/ when you run 'rails generate rspec:install'
    ENV["RAILS_ENV"] ||= 'test'
    require File.expand_path("../../config/environment", __FILE__)
    require 'rspec/rails'
    require 'rspec/autorun'

    # Requires supporting ruby files with custom matchers and macros, etc,
    # in spec/support/ and its subdirectories.
    Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f }

    RSpec.configure do |config|
        # ## Mock Framework
        #
        # If you prefer to use mocha, flexmock or RR, uncomment the appropriate line:
        #
        # config.mock_with :mocha
        # config.mock_with :flexmock
        # config.mock_with :rr

        # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
        config.fixture_path = "#{::Rails.root}/spec/fixtures"

        # If you're not using ActiveRecord, or you'd prefer not to run each of your
        # examples within a transaction, remove the following line or assign false
        # instead of true.
        config.use_transactional_fixtures = true

        # If true, the base class of anonymous controllers will be inferred
        # automatically. This will be the default behavior in future versions of
        # rspec-rails.
        config.infer_base_class_for_anonymous_controllers = false
    end
end

Spork.each_run do
    # This code will be run each time you run your specs.
end

Weiterhin müssen wir die .rspec-Datei, die sich wie eure Gemfile im root-Verzeichnis eurer Ruby on Rails Applikation befindet, anpassen. Dazu fügen wir --drb hinzu, so dass die Datei bzw. deren Inhalt ungefähr so aussehen sollte:

--colour --drb

Damit sagen wir RSpec, dass RSpec den Spork-Server zum Ausführen der Tests nutzen soll.

Spork für Cucumber einrichten

Analog zum Einrichten für RSpec rufen wir als erstes spork cucumber --bootstrap in unserer Konsole auf.

Dann fügen wir wieder den alten Code in den Spork.prefork-Block ein, so dass unsere env.rb (befindet sich im Verzeichnis features/support) ungefähr wie folgt ausschaut:

require 'rubygems'
require 'spork'
#uncomment the following line to use spork with the debugger
#require 'spork/ext/ruby-debug'

Spork.prefork do
    # Loading more in this block will cause your tests to run faster. However,
    # if you change any configuration or code from libraries loaded here, you'll
    # need to restart spork for it take effect.

    # IMPORTANT: This file is generated by cucumber-rails - edit at your own peril.
    # It is recommended to regenerate this file in the future when you upgrade to a 
    # newer version of cucumber-rails. Consider adding your own code to a new file 
    # instead of editing this one. Cucumber will automatically load all features/**/*.rb
    # files.

    require 'cucumber/rails'

    # Capybara defaults to XPath selectors rather than Webrat's default of CSS3. In
    # order to ease the transition to Capybara we set the default here. If you'd
    # prefer to use XPath just remove this line and adjust any selectors in your
    # steps to use the XPath syntax.
    Capybara.default_selector = :css

    # By default, any exception happening in your Rails application will bubble up
    # to Cucumber so that your scenario will fail. This is a different from how 
    # your application behaves in the production environment, where an error page will 
    # be rendered instead.
    #
    # Sometimes we want to override this default behaviour and allow Rails to rescue
    # exceptions and display an error page (just like when the app is running in production).
    # Typical scenarios where you want to do this is when you test your error pages.
    # There are two ways to allow Rails to rescue exceptions:
    #
    # 1) Tag your scenario (or feature) with @allow-rescue
    #
    # 2) Set the value below to true. Beware that doing this globally is not
    # recommended as it will mask a lot of errors for you!
    #
    ActionController::Base.allow_rescue = false

    # Remove/comment out the lines below if your app doesn't have a database.
    # For some databases (like MongoDB and CouchDB) you may need to use :truncation instead.
    begin
        DatabaseCleaner.strategy = :transaction
    rescue NameError
        raise "You need to add database_cleaner to your Gemfile (in the :test group) if you wish to use it."
    end

    # You may also want to configure DatabaseCleaner to use different strategies for certain features and scenarios.
    # See the DatabaseCleaner documentation for details. Example:
    #
    #   Before('@no-txn,@selenium,@culerity,@celerity,@javascript') do
    #     # { :except => [:widgets] } may not do what you expect here
    #     # as tCucumber::Rails::Database.javascript_strategy overrides
    #     # this setting.
    #     DatabaseCleaner.strategy = :truncation
    #   end
    #
    #   Before('~@no-txn', '~@selenium', '~@culerity', '~@celerity', '~@javascript') do
    #     DatabaseCleaner.strategy = :transaction
    #   end
    #

    # Possible values are :truncation and :transaction
    # The :transaction strategy is faster, but might give you threading problems.
    # See https://github.com/cucumber/cucumber-rails/blob/master/features/choose_javascript_database_strategy.feature
    Cucumber::Rails::Database.javascript_strategy = :truncation

end

Spork.each_run do
    # This code will be run each time you run your specs.
end

Des Weiteren muss die Datei cucumber.yml (befindet sich im Verzeichnis config) um --drb angepasst werden, so dass die Datei etwas so aussehen müsste:

<%
rerun = File.file?('rerun.txt') ? IO.read('rerun.txt') : ""
rerun_opts = rerun.to_s.strip.empty? ? "--format #{ENV['CUCUMBER_FORMAT'] || 'progress'} features" : "--format #{ENV['CUCUMBER_FORMAT'] || 'pretty'} #{rerun}"
std_opts = "--format #{ENV['CUCUMBER_FORMAT'] || 'pretty'} --strict --tags ~@wip"
%>
default: --drb <%= std_opts %> features
wip: --drb --tags @wip:3 --wip features
rerun: --drb <%= rerun_opts %> --format rerun --out rerun.txt --strict --tags ~@wip

Spork starten

Zu guter Letzt müssen wir den Spork-Server starten, indem wir in unsere Konsole Folgendes eintippen:

spork rspec

Danach können wir unsere RSpec-Tests ganz normal aufrufen und ausführen lassen, nur mit dem Unterschied, dass die Ausführung jetzt um einiges schneller vonstatten gehen sollte.

Um Spork zum Einsatz für Cucumber zu starten, geben wir Folgendes in unsere Konsole ein:

spork cucumber

Fazit

Ich arbeite grundsätzlich nur mit Spork, wenn ich mit Ruby on Rails und RSpec sowie Cucumber teste, weil es auf meinem System einfach rapide schneller ist als ohne den Einsatz von Spork und TDD/BDD erst so wirklich Spaß macht. Jedoch hängt die Geschwindigkeit der Testausführung von mehreren Faktoren ab.

Beispielweise soll die Ausführung von Cucumber-Tests beim Einsatz von Spork laut Chris Parsons langsamer sein, wenn man mehr als 10 bis 20 Szenarios auf einmal testet, als ohne Spork.

Außerdem scheint seit Ruby 1.9.3 der Einsatz von Spork nicht mehr nötig, wie man auf Taktsoft.com nachlesen kann.

Wie siehts bei euch aus? Habt ihr Spork auch schon zum Beschleunigen eurer Ruby on Rails Tests genutzt?

Kommentare  
0 Kommentare vorhanden
0 Trackbacks/Pingbacks vorhanden
Du bist herzlich eingeladen auch ein Kommentar zu hinterlassen!
Kommentar schreiben

Vielen Dank für dein Kommentar!