Rake Spec without recreating database

This has been asked several times on the list before, but the answer
is always, “That’s dumb, don’t do that”.

“How do I ‘rake spec’ without recreating database?”

I need a real answer. I was hoping that this may be part of the
answer:

Overriding rake test to use migrations instead of rebuilding from
schema.rb:
http://snippets.dzone.com/posts/show/2031

But I don’t want it to do anything at all to the database. Can I just
remove those lines? Every time I forget not to use rake, or as I am
now try to figure out how to use rake I end up completely destroying
my test database and end up having to recreate it.

I am wondering if anyone knows how to actually run rake spec without
having the test database rebuilt. I have several projects that are
connecting to absolutely massive legacy databases. We cannot rebuild
the test version of them from scratch each time, since in order for
the database to function it basically requires that it be a copy of
the production database. Writing migrations for the hundreds of
tables and custom keys, and millions of insertions is not an option
right now.

We have passing tests when we run script/spec spec, but we’d like to
use auto-test, rcov, etc.

Thanks,
Peter B.

You are getting that answer because they are right. That’s what the
test environment is for. The database should be emptied and refilled
with fixture data before each spec runs. Otherwise you’re testing
“dirty” data, and that not good from a testing standpoint. In other
words, each spec/test should begin in a known state. The only way to
guarantee that is to recreate the test database between each spec.

I know that’s not what you wanted to hear, but that’s just the reality
of it. If you decide to hack around with the rake tasks, do so at your
own peril. Don’t expect to get blessings from the developers on this
list.

As far as the legacy database and the test database, you should
definitely not have all the data from production loading and unloading
between each spec. That’s what fixtures, mocks and stubs are for.

In reality your specs should rarely need to touch the database anyway.
You should create mocks and stubs to test against. I’d recommend
looking a bit deeper into rSpec about when an how to touch the test
database. It sounds to me like your putting the cart before the horse.

On Jan 3, 10:38 pm, Robert W. [email protected] wrote:

You are getting that answer because they are right.[…]

Great answer, Robert.

///ark

Robert W. wrote:

You are getting that answer because they are right. That’s what the
test environment is for. The database should be emptied and refilled
with fixture data before each spec runs. Otherwise you’re testing
“dirty” data, and that not good from a testing standpoint. In other
words, each spec/test should begin in a known state. The only way to
guarantee that is to recreate the test database between each spec.

I know that’s not what you wanted to hear, but that’s just the reality
of it. If you decide to hack around with the rake tasks, do so at your
own peril. Don’t expect to get blessings from the developers on this
list.

As far as the legacy database and the test database, you should
definitely not have all the data from production loading and unloading
between each spec. That’s what fixtures, mocks and stubs are for.

In reality your specs should rarely need to touch the database anyway.
You should create mocks and stubs to test against. I’d recommend
looking a bit deeper into rSpec about when an how to touch the test
database. It sounds to me like your putting the cart before the horse.

Having worked with the mother of all legacy databases I have to
disagree. Your logic assumes the production database is under the
developers control. When 28 years of layered government bureaucracy
controls your data you need to test against the real thing not some
sanitized version you create. Case in point is the common practice of
putting configuration data in the database. Trying to accurately
recreate the tables and data in them will introduce more bugs then it
solves.

That having been said, I never had to try to write a Rails App against
such a database. Rails is an opinionated system and when your legacy
data base doesn’t match the opinions, you really are on you own. The
unfortunate answer to your question is that Rails believes it needs to
reset the test database every time because that is what one does in the
“most and best” situation. My suggestions are either to write a custom
rake task, or create a 4th environment to run tests against.

John,

28 years of layered government bureaucracy

So you’ve seen/experienced the Ugly?

My suggestions are either to write a custom
rake task,

I am currently trying to customize the rake task that comes with
rspec_on_rails and finding it much more difficult than I had hoped.

or create a 4th environment to run tests against.

We have written 7 different environments so far, for the various, pre-
live, staging, pre-release, benchmarking, test, and development needs
we have. I am not sure how I could write a test environment such that
it would not recreate my database though. Or did you have something
else in mind?

Peter

As far as the legacy database and the test database, you should
definitely not have all the data from production loading and unloading
between each spec. That’s what fixtures, mocks and stubs are for.

True. So, I’ll norrow down my question and focus on the first in a
line of problems I’m having:
Recreating the database from the schema. Here’s the general
scenario…

Running a rails app with a few new tables of it’s own against a
massive legacy database that is connected to a PHP app.
So to distinguish the tables that are used by the new rails app we
prefix the tables in the database because the PHP coders are SQL
jockeys, and like to hand code all their calls and live on the mysql
prompt:
config.active_record.table_name_prefix = “rb_”

In our models we have to explicitly set the table names and keys of
those models that connect to the ‘legacy’ tables, thus bypassing the
global rb_ prefix:
class User < ActiveRecord::Base
set_table_name ‘member’
set_primary_key ‘memberid’

When the schema.rb is created at rake db:migrate time it is created
correctly (all the table names are correct upon inspection).

However, when other rake tasks are run, like rake spec, for example,
it will attempt to recreate database and prepends all the tables in
schema.rb with our active record prefix, rb_

So now our formerly clean test database has a members table and an
rb_members table.

In reality your specs should rarely need to touch the database anyway.

We have done that. That is EXACTLY why there SHOULD be a way to
ENTIRELY BYPASS the database. Wouldn’t it be nice if we could
decouple testing from the database entirely? That’s what I am
advocating, and I would be very happy to hear of a way to do that.
BUT rspec insists on rebuilding the database even though we’ve got
everything mocked, and won’t be using it.

You should create mocks and stubs to test against. I’d recommend
looking a bit deeper into rSpec about when an how to touch the test
database. It sounds to me like your putting the cart before the horse.

I think people should be able to choose if they want to pull the cart
themselves, just ride the horse and leave the cart behind, or let the
horse pull the cart. I am in complete agreement with convention over
configuration, but I really do need to know how to make rake not
rebuild my database.

I do not have time to write hundreds of migrations for these tables
and ‘convention’ of letting schema.rb rebuild the database doesn’t
work. As I explained above the database is not created the same way
from the schema as the schema is created from the database apparently.

I think that might be a bug in Rails?

Thanks,
Peter B.

On Jan 4, 2008 4:53 PM, Peter B. [email protected] wrote:

global rb_ prefix:
class User < ActiveRecord::Base
set_table_name ‘member’
set_primary_key ‘memberid’

When the schema.rb is created at rake db:migrate time it is created
correctly (all the table names are correct upon inspection).

However, when other rake tasks are run, like rake spec, for example,
it will attempt to recreate database and prepends all the tables in
schema.rb with our active record prefix, rb_

So the problem is actually that you are using schema.rb and the rake
tasks invoked by db:test:prepare don’t honor your tweaking the table
names.

I think that this can actually be easily fixed by setting

 config.active_record.schema_format = :sql

in your config/environment.rb

This will cause rake db:test:prepare to invoke the
db:test:clone_structure task which clones the db using an sql dump
instead of the db:test:clone task which uses db/schema.rb


Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/

I think that this can actually be easily fixed by setting

config.active_record.schema_format = :sql

in your config/environment.rb

This will cause rake db:test:prepare to invoke the
db:test:clone_structure task which clones the db using an sql dump
instead of the db:test:clone task which uses db/schema.rb

Rick,

That probably would work. But our database is massive. Our
development database is effectively a copy of our live database due to
other requirements and simultaneous work on the live and development
databases from other sources (PHP and SQL developers). Dumping the
development database and importing to a test database takes several
hours (shared development database on our development database server,
accessed over TCPIP). It just isn’t an efficient way to run ‘rake
spec’. Half my day would be gone just to see if my tests pass.

However, I have found the solution!

vendor/plugins/respec_on_rails/tasks/rspec.rake

Line #9 before:
spec_prereq = File.exist?(File.join(RAILS_ROOT, ‘config’,
‘database.yml’)) ? “db:test:prepare” : :noop

Line #9 after:
spec_prereq = :noop

Now my database is no longer being rebuilt. I can run rake spec and
rcov and auto-test

So I hope this helps others who find a need to be unconventional!

Peter B.

Thanks for the tip Peter. I always find it extemely annoying that rspec
recreates my test database from scratch when all I want to do is run
tests on a specific controller using mock objects. I really feel an
option (or logic) should be added to the task to prevent it from doing
this when a none model file is passed to rake.

On Mon, Apr 7, 2008 at 2:31 PM, Basim Reza
[email protected] wrote:

Thanks for the tip Peter. I always find it extemely annoying that rspec
recreates my test database from scratch when all I want to do is run
tests on a specific controller using mock objects. I really feel an
option (or logic) should be added to the task to prevent it from doing
this when a none model file is passed to rake.

RSpec wraps the testing infrastructure that comes with Rails, so the
place to address this is in Rails proper, not in RSpec. I’d recommend
contributing a patch to the Rails project.

Good luck,
David

“How do I ‘rake spec’ without recreating database?”

erm… this seems too obvious… but what’s wrong with typing
‘script/spec spec/’?

Robert W. wrote:
[…]

In reality your specs should rarely need to touch the database anyway.
You should create mocks and stubs to test against. I’d recommend
looking a bit deeper into rSpec about when an how to touch the test
database. It sounds to me like your putting the cart before the horse.

I have tried this approach and found that it involved far too much
mocking for my liking, so that I was testing my mocks, not my app. How
do you manage to make this work?

Best,
–Â
Marnen Laibow-Koser
http://www.marnen.org
[email protected]

Peter B. wrote:
[…]

I am wondering if anyone knows how to actually run rake spec without
having the test database rebuilt. I have several projects that are
connecting to absolutely massive legacy databases. We cannot rebuild
the test version of them from scratch each time, since in order for
the database to function it basically requires that it be a copy of
the production database. Writing migrations for the hundreds of
tables and custom keys, and millions of insertions is not an option
right now.

Then you have two options, both of which are better than the route you
are taking.

  1. If your DB server allows it, put the ugly parts of the DB in a
    template. I do this for a Rails app in which I use PostGIS, which adds
    lots of tables to the DB that I didn’t want to make into fixtures. So
    when the test DB is dropped and recreated, it starts out life as a fresh
    copy of my PostGIS template DB, with just the PostGIS tables.

  2. Mock the legacy models instead of having actual tables.

What you are doing is a recipe for unreliable tests. That’s dumb; don’t
do that. :slight_smile:

We have passing tests when we run script/spec spec, but we’d like to
use auto-test, rcov, etc.

Thanks,
Peter B.

Best,
–Â
Marnen Laibow-Koser
http://www.marnen.org
[email protected]

Marnen Laibow-Koser wrote:

Robert W. wrote:
[…]

In reality your specs should rarely need to touch the database anyway.
You should create mocks and stubs to test against. I’d recommend
looking a bit deeper into rSpec about when an how to touch the test
database. It sounds to me like your putting the cart before the horse.

I have tried this approach and found that it involved far too much
mocking for my liking, so that I was testing my mocks, not my app. How
do you manage to make this work?

Hum. It looks like at the time I posted this I apparently left out an
important point. What I should have said is that controller, view some
other specs can rely on mocking/stubbing. I using them heavily in these
specs. Model specs do need to hit the database.

I’ve also moved to using factories rather than fixtures for my specs.
I’ve been using factory_girl with rSpec for my work.

This is my last comment on this tread. I still hold to my original
opinion as expressed in my first reply (with this small correction).
It’s fine if others disagree with me. I won’t lose sleep over it. :slight_smile:

Marnen Laibow-Koser wrote:

I wasn’t trying to start a fight – I just wanted to learn some more
about your testing practices, so I’m not sure what provoked that
paragraph.

Oops. Sorry that was not directed to you at all Marnen. I was simply
trying to say I have exhausted my opinion on the original post, about
resetting data to a known state before each test runs.

Now I’m done. I promise. :wink:

Robert W. wrote:

Marnen Laibow-Koser wrote:

Robert W. wrote:
[…]

In reality your specs should rarely need to touch the database anyway.
You should create mocks and stubs to test against. I’d recommend
looking a bit deeper into rSpec about when an how to touch the test
database. It sounds to me like your putting the cart before the horse.

I have tried this approach and found that it involved far too much
mocking for my liking, so that I was testing my mocks, not my app. How
do you manage to make this work?

Hum. It looks like at the time I posted this I apparently left out an
important point. What I should have said is that controller, view some
other specs can rely on mocking/stubbing.

Oh, see, I no longer write controller or view specs much. Cucumber
mostly replaces them.

I using them heavily in these
specs. Model specs do need to hit the database.

I’ve also moved to using factories rather than fixtures for my specs.
I’ve been using factory_girl with rSpec for my work.

Yeah, I recently switched from mock_model to Machinist.

I’m curious: how do you use factories with mocks? They seem to cry out
for real records.

This is my last comment on this tread. I still hold to my original
opinion as expressed in my first reply (with this small correction).
It’s fine if others disagree with me. I won’t lose sleep over it. :slight_smile:

I wasn’t trying to start a fight – I just wanted to learn some more
about your testing practices, so I’m not sure what provoked that
paragraph.

Best,
–Â
Marnen Laibow-Koser
http://www.marnen.org
[email protected]