How to stop rspec from dropping the test database before tests - ruby-on-rails

I have two Rails apps that use the same database. One app is managing the database through migrations but the other is just accessing it.
For some reason when I run tests with RSpec in the app that is not managing the database it drops the database before running the tests. But because this app does not know how to recreate the database all tests will fail.
How can I tell RSpec not to drop the database, just use it as it is?

If you don't need to migrate the database you can redefine rspecs-rails
spec:prepare task like this:
lib/tasks/patch_rspec_rails.rb
Rake::Task["spec:prepare"].clear
namespace :spec do
task :prepare do
ENV['RACK_ENV'] = ENV['RAILS_ENV'] = 'test'
end
end
The original spec:prepare task callstest:prepare, which setups the db.
The task test:prepare exists since Rails 4.0 (or maybe earlier). This task also exists within Rails 5.0. It is a hook for railsties to add test dependent setups. You can check its definition with rake -W test:prepare. That
the task is hit you can check with rake --trace spec.
ActiveRecord uses this task to check the migration state and setup the db.
When this task is not called, no db will be dropped or created.
But be aware, when some other gem uses test:prepare as a hook too plug into tests, it will not work.
Edit:
Since Rails 4.1 you can set config.active_record.maintain_test_schema = false within config/environments/test.rb. This way Rails should no longer try to migrate your test schema.

Ideally RSpec should be reinitialisation the database for testing to ensure your environment is in a reliably, predictable state.
What you could do is for the Rails app that isn't managing the database carry out a rake db:schema:dump to generate the schema.rb which will then be used by RSpec - of course make sure that your database.yml test configuration isn't pointing to your live database.
I know that this isn't technically a solution to your question but it should prevent the underlying issue which is causing your tests to fail.

Related

How to make db:test:purge only drop a schema on postresql?

I'm using postgresql on a rails 3 app. I've been using sqlite3 for test environment, but decided to finally switch to the same db I use in production for testing purposes. Problem is, I'm only creating one database and diverse schemas for each environment. This is somethiing I can't change, since the environment is enterprise-constrained.
Hence, I have a test schema. I rund db:schema:load on it and it works fine. I run rake spec on it (I'm using rspec) and it breaks, exactly on the 'db:test:purge' task which comes from rails. Now, this task drops the database. Not only is the database owner different from the schema owner in my case, I'd rather have the task recreate the schema instead of recreating the database.
How can I do this?
Actually there is no real solution for this problem, since rails by default erases the database. It expects this database not to be shared with production (and they might have a point). Nevertheless, I found some interesting links and the way is to patch the rake task. Following the patch and links:
namespace :db do
namespace :test do
task :purge do
ActiveRecord::Migration.verbose = false
Rake::Task["db:schema:load"].invoke
end
end
end
https://github.com/rails/rails/issues/12117#issuecomment-25961999
Run Rails Tests without Dropping Test Database
http://www.pervasivecode.com/blog/2007/09/22/making-rails-raketest-not-drop-your-pgsql-database/
This is not a direct answer to your question, but you can use rspec command instead of rake spec. rspec command doesn't purge your database.

Rake in Rails: should I be using db:reset?

I'm a little confused by the intended use of the default Rails Rake tasks, and would like advice on whether I should be using db:reset or writing a custom Rake task. Nothing clever, just daily housekeeping, and I may well be missing an obvious doc as I'm new to Rails.
My problem: I want to throw away my database and run from a completely clean setup, in order that I can be sure the database contains known data only. This is useful for demo prep, for debugging, and for making sure Jenkins is comparing like-with-like in tests.
Currently, I'm writing this:
bin/rake db:drop:all db:create:all db:migrate db:seed db:test:prepare
This is a lot to type, but leaves seed data only in both dev and test databases. I am unsure how this differs from db:reset, which would be more convenient to type.
Should I use db:reset or write a custom db:from_scratch task?
You should be using:
rake db:reset
This will drop the database, recreate it and load the current schema into it.
For a full list of rake db tasks:
rake --describe db
If your requirements change then it would be better to write a custom rake task, where you can apply your own customisation.
If you're not sure what a rake task does, then I would suggest not using it. In this case, you're probably ok, however db:reset is not the equivalent to what you are doing above. db:reset recreates the database from scheme.rb, this may be different as you could have written migrations that have not yet been run.
I would suggest that you use a custom rake task, you can then modify it to fit your exact purposes, especially if you want to perform other tasks as well (for example tagging in git)
What you are trying to achieve in your the tasks you are running through rake is setting both the test and the development databases. rake db:reset will just do it for your current environment db according to the schema.rb and then load the seeds data into the db. The schema.rb in general is never edited, its for a know-only/refer-only purpose, however some people do tend have different schema.rb which might create a problem :(. What sounds better to me is if you need to set both your development and test database, then run your migrations for the dev environment and use the schema.rb to create the test environment db. I would definitely suggest you to get a second opinion from some Rails guru though to find out a real perfect way to achieve what you want.
rake db:reset
This will drop the database, recreate it and load the current schema into it.
rake db:reset will run rake db:seed
Example :
if you have seed file that you wrote after you ran your migration , it will run that too.

How to test rake tasks, cron jobs, and

I know in Rails application, I can write tests for controllers and models by using Rspec.
But:
How about to test some rake task? What is the good way to test some rake task?
How about to test a cron job which run certain rake task every day at a fixed time?
Can Rspec also be used for above two scenarios in Rails app development or are there some other ways to implement those tests?
In addition:
I have a rake task which is used to update the database of the Rails app by fetching data from another database and insert to the app database (clean the app database first of course)
I would like to test these, how to do it?
Instead of having code in your rake tasks, do something like this:
desc "Charge Customers Daily"
task :charge_customers => :environment do
CustomerCharges.create
end
That way, you can write rspec tests in the customer_charges_spec.rb file as you normally would.
Maybe this helps :
http://www.philsergi.com/2009/02/testing-rake-tasks-with-rspec.html
To test a cron job, you can just redirect to a log file on cron itself, like :
command > /tmp/log.txt 2>&1
Generally, if you intend on doing db insertions and stuff in a rake task, i would reconsider and write that as a separate ruby module. I think it's much more flexible this way.

Rails 3 Rake Clone Database for Testing Environment

Is there a rake command in Rails 3 to clone my development database data? I noticed rake db:test:prepare and rake db:test:clone are mentioned throughout various blogs, but running them seems to do nothing. Furthermore, rake -T shows no db:test cases. I've resorted to loading a sql dump for now, but it would be great if I could just clone my existing development data for up-to-date testing.
EDIT --
I desire to test on a database since I am dealing with legacy data that I run through model filters when accessed. Factories won't work for me in this context, since data passed through create is defined as a different schema than that of the legacy data.
rake db:test:prepare is still there even though it doesn't show up in rake -Tdb. I guess the Rails team decided to de-clutter the rake -T output?
I would suggest you not clone your development database but rather rely on factories to give you predictable data you can craft for your exact test cases. Sooner or later, relying on having reliable test data in a database you can access will break your tests. It will also break the tests of anyone else who works on the project. And changes/additions to the data will not propagate to other developers as would your carefully constructed factories.
Look over Machinist, FixJour, FactoryGirl and the lot. They really solve the test data problem well and you check them into version control so the rest of your team has access to them.

Rails 2.3.2 unit test passes when run with normal ruby, fails when run with rake test:units

When creating a record in a unit test, I'm getting an 'ActiveRecord::RecordInvalid' when it's run with rake test:units. I don't get this error when I run the unit test manually with ruby ('ruby unit/blah_test.rb'). I've narrowed the issue down to a validation that exists in my model. It is an inclusion validation which is actually performing a find against a different model to get the valid values. I'm thinking this is related to the fixtures not being loaded in time, but I do have 'fixtures :all' in my test_helper.rb (I've also tried including 'fixtures :all' in the unit test itself.
Does anyone have any suggestions on how I can try to narrow this down even further?
Thanks.
Certainly what you are seeing would fit with fixtures being missing. With rake test:units the test database schema will be set up (and cleared) so your included model's fixtures may not be populated. With the direct call you'll be using the test database in the state you last left it which probably does include the fixutres for the included model.
Is there another call to fixtures in the test class which may be causing fixtures :all not to kick in?
You could try doing rake db:test:prepare prior to running your test via ruby which would mean you were running on a fresh test database. This would further highlight if the fixtures aren't being loaded for your included model.

Resources