Validate all Fixtures

UPDATE: Please have a look at valid_attributes

A enhancement to the validate all models task , adds a db:validate_fixtures, which basically loads the fixtures and then validates all models.


To make this work for RSpec you have to “ln -s PATH_TO/spec/fixtures test/fixtures”.

Output:

-- records - model --
         1x FtpAccount
         2x Movie
Movie: id=2
["Title can't be blank"]
         1x Order
         1x Rating
No Table for: Tableless
         4x User

Task:

#base: http://blog.hasmanythrough.com/2006/8/27/validate-all-your-records
#task: rake db:validate_models
namespace :db do
  def all_models
    #get all active record classes
    Dir.glob(RAILS_ROOT + '/app/models/**/*.rb').each do |file|
      begin
        require file unless file =~ /observer/
      rescue
        #require any possible file dependencies
        if $!.to_s =~ /^uninitialized constant (\w+)$/
          require $1.underscore + '.rb'
          retry
        else
          raise
        end
      end
    end
    klasses = Object.subclasses_of(ActiveRecord::Base)
    #throw out session if it is not stored in db
    klasses.reject! do |klass|
      klass == CGI::Session::ActiveRecordStore::Session && ActionController::Base.session_store.to_s !~ /ActiveRecordStore/
    end
    klasses.select{ |c| c.base_class == c}.sort_by(&:name)
  end

  def validate_models
    #validate them
    puts "-- records - model --"
    all_models.each do |klass|
      begin
        total = klass.count
      rescue
        #tableless, session...
        if $!.to_s =~ /Table .* doesn't exist/im
          puts "No Table for: #{klass}"
          next
        end
        raise
      end
      printf "%10dx %s\n", total, klass.name
      chunk_size = 1000
      (total / chunk_size + 1).times do |i|
        chunk = klass.find(:all, :offset => (i * chunk_size), :limit => chunk_size)
        chunk.reject(&:valid?).each do |record|
          puts "#{record.class}: id=#{record.id}"
          p record.errors.full_messages
          puts
        end rescue nil
      end
    end
  end

  desc "Run model validations on all model records in database"
  task :validate_models => :environment do
    validate_models
  end

  desc "Load and validate fixtures (and other models)"
  task :validate_fixtures do
    RAILS_ENV='test'
    
    Rake::Task[:environment].invoke
    Rake::Task["db:fixtures:load"].invoke
    
    validate_models
  end
end

Testing a single Example; Spec; Testcase; Test

UPDATE: everything is now on github

Testing a single spec, a single test, a single testcase or a single example is a great timesaver when debugging a small problem while having a large testsuite, or a testsuite with a lot of failures…

  • rake test:blog -> only the Blog Testcase
  • rake spec:blog -> only the Blog Spec
  • rake test:blog:create -> only the tests matching /create/ in Blog
  • rake spec:blog:delete -> only the first example matching /create/ in Blog
  • rake test:’admin/blogs_con’ -> only BlogsController Test in admin folder
  • rake test:xy -> first test matching xy*_test.rb (searched in order: unit,functional,integration,any folder)

It will search in unit/functional/integration (test) and models/controllers/views/helpers(spec).
Idea

Install:
UPDATE: everything is now on github

Intelligent Redirects: redirect_to_last_index

I often came across the same problem, the user starts say /users?order=email%20desc, chooses the user to edit and when he hits save/destroy he finds himself at /users/, very disturbing…. Another example comes from multiple controllers, when you start in /movies/3 and then, edit the user that created the movie, hit save and you resurface in /users/.

Fixing this redirecting issue was easier then i thought, and i refactored it to be a nice drop in and forget solution!

#app/application_controller.rb
...
  after_filter :save_last_index , :only => :index

protected
  def redirect_to_last_index
    return redirect_to session[:last_index] if session[:last_index]
    redirect_to :action => :index
  end

  def save_last_index
    session[:last_index]=request.request_uri
  end
...

#app/users_controller.rb
  def destroy
    @user = User.find(params[:id]).destroy
    redirect_to_last_index
  end

No more redirecting pain hurray 😀

Live example

Installing RCov by script

Code coverage analysis with RCov, next on my TODO :>
Another install script for your leisure…

OBSOLETE: gem install rcov works again!

wget http://rubyforge.org/frs/download.php/28270/rcov-0.8.1.2.tar.gz
tar -xf rcov-0.8.1.2.tar.gz
sudo ruby rcov-0.8.1.2/setup.rb
rm -rf rcov-0.8.1.2

svn cleanup
svn update
piston import http://svn.codahale.com/rails_rcov vendor/plugins/rails_rcov

Now you can get started with rake test:units:rcov

Unit test results

  • Show only selected parts: SHOW_ONLY=m,l,c,v //model,lib,controller,view
  • Run single tests: rcov FILE -exclude “/var/|/usr/” –rails (irgnore /var and /usr folder)
  • Add RCov parameters: RCOV_PARAMS=””
  • exclude RCOV_PARAM=”–exclude ‘var/*,gems/*'”
  • Sort by coverage: COV_PARAMS=”–sort=coverage”
  • Hide fully covered: RCOV_PARAMS=” –only-uncovered”
  • If you see something like (eval):580:in `attribute’: wrong number of arguments (2 for 0) (ArgumentError) it means one of your tests is uncoverable, this can happen while using SQS gem

Add the RCOV_PARAMS to spec/rcov.opts (or test/rcov.opts)