RAILS: running code once after loading all global fixtures - ruby-on-rails

Where can I write code to be executed only once after loading of all global fixtures, and before running any tests/specs
I tried before(:suite) with rspec 1.3.1 on Rails 2.3.11 and that seems to get executed before fixtures.

How about a rake task(/lib/tasks) ? For instance, i have one(reset_db.rake) that loads fixtures, resets db and more :
namespace :db do
desc "Drop, create, migrate, seed the database and prepare the test database for rspec"
task :reset_db => :environment do
Rake::Task['db:drop'].invoke
Rake::Task['db:create'].invoke
Rake::Task['db:migrate'].invoke
Rake::Task['db:fixtures:load'].invoke
Rake::Task['db:test:prepare'].invoke
end
end

I run into the same issue, but still haven't found any way to hook up some code after loading fixtures ... so i used the SpyrosP solution. However the problem with this way of doing is that you can't benefit anymore of the fixtures accessors helpers, since you don't load your fixtures from the rspec config but from a rake task.
So basically you neeed to recreate theese helpers like that (code is a bit dirty but seems to work for me :
#spec_helper.rb
module CustomAccessors
# Remplacement de fixtures :all
%w{yml csv}.each do |format|
paths = Dir.
glob(::Rails.root.join("spec/fixtures/*.#{format}")).
map! { |path| path.match(/\/([^\.\/]*)\./)[1] }
paths.each do |path|
define_method path do |*args|
path.singularize.camelcase.constantize.find(ActiveRecord::Fixtures.identify(args[0]))
end
end
end
end
RSpec.configure do |config|
#config.fixture_path = "#{::Rails.root}/spec/fixtures"
config.use_transactional_fixtures = true
config.include(CustomAccessors)
end

Related

Rails 4.2 run rake task after ActiveRecord load

I have some data, which I want to pre-load in my add on booting. I've made an rake task and it works good. I tried to put code in config/initializers but it starts too early (I need all models to be loaded). after_initialize is not good too for me. I place code example lower
require 'rake'
load File.join(Rails.root, 'lib', 'tasks', 'rights.rake')
Rake::Task['dev:create_rights'].invoke
So, where is good place to put this code? Of course I can put it in AR::Base or so on, but it is ugly.
Here is the task, if It will help.
namespace :dev do
desc "Creation of the minimal rights"
task :create_rights => :environment do
klasses = ActiveSupport::DescendantsTracker.descendants(AbstractModel)
default_rights = RightsList.default_rights
Role.includes(:rights).all.each do |role|
klasses.reject{|klass| role.rights.pluck(:klass_name).include? klass.underscore }.each do |klass|
Right.create role: role, klass_name: klass.underscore, rights_per_class: default_rights
end
end
end
end
Thank you
UPDATE
Got dirty solution with adding in config/application.rb
config.after_initialize do
require 'rake'
load File.join(Rails.root, 'lib', 'tasks', 'rights.rake')
Rails.application.eager_load!
Rake::Task['dev:create_rights'].invoke
end
And I understand that it is still wrong way. Is here good way?

Rails custom environment: keep certain subdirectories in app/models from loading

I've created a custom environment in the Rails app I'm working on called nhl_test. The models for this environment are in app/models/nhl namespace. There are a number of other models in app/models/[other_subdir] that I don't want to autoload in this environment. So far I tried modifying the config.paths in my environment file similarly to how I modified the db/migrate location, like so:
config/environments/nhl_test.rb
MyApp::Application.configure do
config.eager_load = false
config.paths["db/migrate"] = ["db/migrate/nhl"]
config.paths["app/models"] = ["app/models/nhl"]
end
However, the other subdirectories of app/models are still being loaded. I can tell because there is code in those models that will break in this environment and I'm unable to run my tests using RAILS_ENV=nhl_test m test/models/nhl - they break with a stack trace that points to app/models/mlb/base.rb.
How can I keep any of the models except what's in app/models/nhl from being loaded in this environment??
EDIT It turns out it's this line in test_helper.rb that is causing the problem:
class ActiveSupport::TestCase
fixtures :all
end
Rather than loading all fixtures, I just need to load the fixtures in test/fixtures/nhl somehow...
I've tried the following but it doesn't seem to be working:
class ActiveSupport::TestCase
fixture_path = Rails.root.join('test', 'fixtures', 'nhl')
fixtures :all
end
I was able to fix the problem by setting the fixture_path this way:
# test_helper.rb
ActiveSupport::TestCase.fixture_path = Rails.root.join('test', 'fixtures', Rails.env.gsub('_test', ''))
class ActiveSupport::TestCase
fixtures :all
end

Testing a method defined in a rake task

I want to test a method defined in a rake task.
rake file
#lib/tasks/simple_task.rake
namespace :xyz do
task :simple_task => :environment do
begin
if task_needs_to_run?
puts "Lets run this..."
#some code which I don't wish to test
...
end
end
end
def task_needs_to_run?
# code that needs testing
return 2 > 1
end
end
Now, I want to test this method, task_needs_to_run? in a test file
How do I do this ?
Additional note: I would ideally want test another private method in the rake task as well... But I can worry about that later.
The usual way to do this is to move all actual code into a module and leave the task implementation to be only:
require 'that_new_module'
namespace :xyz do
task :simple_task => :environment do
ThatNewModule.doit!
end
end
If you use environmental variables or command argument, just pass them in:
ThatNewModule.doit!(ENV['SOMETHING'], ARGV[1])
This way you can test and refactor the implementation without touching the rake task at all.
You can just do this:
require 'rake'
load 'simple_task.rake'
task_needs_to_run?
=> true
I tried this myself... defining a method inside a Rake namespace is the same as defining it at the top level.
loading a Rakefile doesn't run any of the tasks... it just defines them. So there is no harm in loading your Rakefile inside a test script, so you can test associated methods.
When working within a project with a rake context (something like this) already defined:
describe 'my_method(my_method_argument)' do
include_context 'rake'
it 'calls my method' do
expect(described_class.send(:my_method, my_method_argument)).to eq(expected_results)
end
end

How to write unit test cases for rake tasks in rails?

Hi all I have this situation , I need to write unit test cases for rake tasks in my rails application but i could not figure out a way to do that. Did any one try that ?
What you can do is this..
Write your logic which will run on a rake task inside a model or class.
Write unit test for that model.
Finally call that method inside your rake task.
I found out this link for writing test cases using rspec.
Short and crisp test cases
Basically, create a module which will parse the name of the rake task, and make us available the keyword task, on which we could call expect { task.execute }.to output("your text\n").to_stdout
Here's how you will create the file,
module TaskExampleGroup extend ActiveSupport::Concern
included do
let(:task_name) { self.class.top_level_description.sub(/\Arake /, "") }
let(:tasks) { Rake::Task }
# Make the Rake task available as `task` in your examples:
subject(:task) { tasks[task_name] }
end
end
Add this in the rspec initializer file
RSpec.configure do |config|
# Tag Rake specs with `:task` metadata or put them in the spec/tasks dir
config.define_derived_metadata(:file_path => %r{/spec/tasks/}) do |metadata|
metadata[:type] = :task
end
config.include TaskExampleGroup, type: :task
config.before(:suite) do
Rails.application.load_tasks
end
end

How to load db:seed data into test database automatically?

I'm attempting to use the new standard way of loading seed data in Rails 2.3.4+, the db:seed rake task.
I'm loading constant data, which is required for my application to really function correctly.
What's the best way to get the db:seed task to run before the tests, so the data is pre-populated?
The db:seed rake task primarily just loads the db/seeds.rb script. Therefore just execute that file to load the data.
load "#{Rails.root}/db/seeds.rb"
# or
Rails.application.load_seed
Where to place that depends on what testing framework you are using and whether you want it to be loaded before every test or just once at the beginning. You could put it in a setup call or in a test_helper.rb file.
I'd say it should be
namespace :db do
namespace :test do
task :prepare => :environment do
Rake::Task["db:seed"].invoke
end
end
end
Because db:test:load is not executed if you have config.active_record.schema_format = :sql (db:test:clone_structure is)
Putting something like this in lib/tasks/test_seed.rake should invoke the seed task after db:test:load:
namespace :db do
namespace :test do
task :load => :environment do
Rake::Task["db:seed"].invoke
end
end
end
I believe Steve's comment above should be the correct answer. You can use Rails.application.load_seed to load seed data into your test envoironment. However, when and how often this data is loaded depends on a few things:
Using Minitest
There is no convenient way to run this file once before all tests (see this Github issue). You'll need to load the data once before each test, likely in the setup method of your test files:
# test/models/my_model_test.rb
class LevelTest < ActiveSupport::TestCase
def setup
Rails.application.load_seed
end
# tests here...
end
Using RSpec
Use RSpec's before(:all) method to load seed data for all test for this model:
describe MyModel do
before(:all) do
Rails.application.load_seed
end
describe "my model..." do
# your tests here
end
Hope this helps.
Building on Matt's answer, if taking that sort of route, I recommend calling Rails.application.load_seed in a before(:suite) block in rspec_helper.rb rather than in a before(:all) block in any file. That way the seeding code is invoked only once for the entire test suite rather than once for each group of tests.
rspec_helper.rb:
RSpec.configure do |config|
...
config.before(:suite) do
Rails.application.load_seed
end
...
end
We're invoking db:seed as a part of db:test:prepare, with:
Rake::Task["db:seed"].invoke
That way, the seed data is loaded once for the entire test run, and not once per test class.
Adding Rake::Task["db:seed"].invoke to the db:test:prepare rake task did not work for me. If I prepared the database with rake db:test:prepare, and then entered the console within the test environment, all my seeds were there. However, the seeds did not persist between my tests.
Adding load "#{Rails.root}/db/seeds.rb" to my setup method worked fine, though.
I would love to get these seeds to load automatically and persist, but I haven't found a way to do that yet!
For those using seedbank, it changes how seeds are loaded, so you probably can't/don't want to use the load ... solution provided here.
And just putting Rake::Task['db:seed'].invoke into test_helper resulted in:
Don't know how to build task 'db:seed' (RuntimeError)
But when we added load_tasks before that, it worked:
MyApp::Application.load_tasks
Rake::Task['db:seed'].invoke

Resources