Ruby Forum RSpec > Specifying certain tables NOT to be cleared each example?

Posted by Andrew Selder (aselder)
on 22.05.2008 04:55
(Received via mailing list)
Is it possible to specify that certain tables not be cleared on each
example.

I've inherited a project where a good amount of enumerated data is
stored in the database (US States, statuses, about 15-20 tables worth.
Over all, it's a reasonable decision that leads to solid production
code (acts_as_enumerated is good). This data is read-only and
relatively static; any changes to these tables are done via migrations.

The problem comes when I'm writing my tests. Obviously all these
tables get wiped with each example. Yes, I could specify these as
fixtures, but I really don't want to have to specify 15-20 fixtures on
every example. Yes, I could mock/stub all the values, except that I
use many of these values at class definition time, which means that
errors are thrown before I can even mock/stub.

For instance, I have a statement like this.

  named_scope :open, :conditions => ["lead_status_id IN (?)", %w{New
Incubating Client UAG}.collect{|x| LeadStatus[x].id}]

Which loads the named_scope using the string version of the
enumeration for clarity's sake. It works great, except for testing.

Does anybody see anyway around this other than creating a fixture file
for each of these tables and loading all the fixtures on each describe
block. Not only does this make for ugly code, but I'm sure it takes a
good chunk of time to setup and teardown each of the tables each
example.

It would be wonderful if there was some option to specify tables that
behave like this, that should be loaded at the beginning of the test
run, and (optionally) trashed at the end of the run. Or even better,
specify that the test script shouldn't touch (build or teardown) these
tables at all, and let their migrated state remain.

Thanks,

Andrew
Posted by Scott Taylor (Guest)
on 22.05.2008 06:59
(Received via mailing list)
On May 21, 2008, at 10:49 PM, Andrew Selder wrote:

> The problem comes when I'm writing my tests. Obviously all these  
>
> that behave like this, that should be loaded at the beginning of the  
> test run, and (optionally) trashed at the end of the run. Or even  
> better, specify that the test script shouldn't touch (build or  
> teardown) these tables at all, and let their migrated state remain.
>

AFAIK, any data that goes into the test database *after* the
db:test:prepare rake task, but *before* the spec rake task will not
get wiped out with every test case.

Rails' Fixtures do not get reloaded every test case, but every test
case will get loaded into a transaction, so any data which is modified
in those test cases should get rolled back.

I don't see any reason why you couldn't have a factory method which
would set up that data, make a rake task out of it, and set it the
dependency for the spec task:

task :spec => :setup_test_data

One problem with this solution is that it precludes any ability to run
with a single test with script/spec or with autotest.

Another option (although, I'm sure that it will be quite slow) is to
define a global before(:each) in spec/spec_helper.rb:

Spec::Runner.configure do |config|
   config.use_transactional_fixtures = true
   config.use_instantiated_fixtures  = false

   before(:each) do
    # setup_test_data...
   end
end

Scott
Posted by Ashley Moran (Guest)
on 22.05.2008 13:09
(Received via mailing list)
On 22 May 2008, at 03:49, Andrew Selder wrote:

> It would be wonderful if there was some option to specify tables  
> that behave like this, that should be loaded at the beginning of the  
> test run, and (optionally) trashed at the end of the run. Or even  
> better, specify that the test script shouldn't touch (build or  
> teardown) these tables at all, and let their migrated state remain.


Like Scott said, this shouldn't be a problem.  Are you creating your
test DB like this?
   rake db:test:clone

If so, try this:
   rake db:migrate RAILS_ENV=test

It will create a test database that is identical to a new production
database, instead of an approximation.  I have no idea why the Rails
team decided would be better to test against an incomplete database,
but I always use migrate now, instead of clone.

Ashley

--
http://www.patchspace.co.uk/
http://aviewfromafar.net/
Posted by Andrew Selder (aselder)
on 22.05.2008 15:28
(Received via mailing list)
Ashley,

I am using rake db:migrate RAILS_ENV=test.

The values I'm inserting into the tables using migrations are gone by
the time the tests run.

Andrew
Posted by David Chelimsky (Guest)
on 22.05.2008 15:39
(Received via mailing list)
On May 21, 2008, at 9:49 PM, Andrew Selder wrote:

> The problem comes when I'm writing my tests. Obviously all these  
> tables get wiped with each example.

This should not be the case. Transactions get rolled back, but tables
do not just get wiped clean.

If this static data is being generated in migrations, then you should
be OK. Is it?
Posted by Andrew Selder (aselder)
on 22.05.2008 15:57
(Received via mailing list)
David,

The static data generated in the migrations in being wiped away.

I did a
rake db:test:purge

followed by

rake db:migrate RAILS_ENV=test

and then looked in my database to verify that the data was there and
it was.

And then when I run rake spec, the test blow up and I looks at the DB
and all the static tables are empty.

Looking at the rspec.rake file in the rspec_on_rails plugin, the spec
task calls the spec_prereq task. This task does a db:test:prepare,
which looking at the source for that in the rails gem only copies the
schema from the development db.

I'm using Rails 2.1 RC1, and the tagged CURRENT version of both plugins.

Thanks,

Andrew
Posted by David Chelimsky (Guest)
on 22.05.2008 15:58
(Received via mailing list)
On Thu, May 22, 2008 at 8:55 AM, Andrew Selder <aselder@mac.com> wrote:
>
> I'm using Rails 2.1 RC1, and the tagged CURRENT version of both plugins.
AHA!

CURRENT means the latest release, which is 1.1.3, which was released
months ago, before Rails 2.1 RC1.

Try the latest from github:

script/plugin install git://github.com/dchelimsky/rspec.git
script/plugin install git://github.com/dchelimsky/rspec-rails.git
script/generate rspec

See if that makes any difference.

Cheers,
David
Posted by Andrew Selder (aselder)
on 22.05.2008 16:13
(Received via mailing list)
Downloaded the latest plugins from Github and got the same results.

The spec rake task still ends up calling db:test:prepare which blows
away the database and reloads only the schema.

Thanks,

Andrew
Posted by Pat Maddox (pergesu)
on 22.05.2008 16:24
(Received via mailing list)
Have you tried making it not call db:test:prepare?
Posted by David Chelimsky (Guest)
on 22.05.2008 16:28
(Received via mailing list)
On Thu, May 22, 2008 at 9:12 AM, Andrew Selder <aselder@mac.com> wrote:
> Downloaded the latest plugins from Github and got the same results.
>
> The spec rake task still ends up calling db:test:prepare which blows away
> the database and reloads only the schema.

Well, thanks for trying.

You can't be the first person to run up against this problem. I've run
into it before but not in any rails apps I've worked on.

Sounds like the solution would be something like what Scott and Ashley
are talking about - introducing rake db:migrate or a custom data setup
task after or instead of db:test:prepare.
Posted by Ashley Moran (Guest)
on 22.05.2008 17:12
(Received via mailing list)
On 22 May 2008, at 15:25, David Chelimsky wrote:

> Sounds like the solution would be something like what Scott and Ashley
> are talking about - introducing rake db:migrate or a custom data setup
> task after or instead of db:test:prepare.

It just occurred to me that I never ran any rake tasks to run the
specs- I always used autotest.  If the rake task behaviour is a "bug"
then running autotest won't fix that, but it might get around the
issue of your database being cleared out.

Andrew - do you use autotest in general?  If so do you see the same
behaviour with it?

Ashley


--
http://www.patchspace.co.uk/
http://aviewfromafar.net/
Posted by Andrew Selder (aselder)
on 22.05.2008 17:14
(Received via mailing list)
I tried modifying rspec.rake to read

spec_prereq = File.exist?(File.join(RAILS_ROOT, 'config',
'database.yml')) ? [:testing, "db:test:purge", "db:migrate"] : :noop
task :noop do
end

task :testing do
   RAILS_ENV = ENV['RAILS_ENV'] = 'test'
end

which should do what I want, I think. However the db:migrate task
blows up with a message:

rake aborted!
Mysql::Error: No database selected: SHOW TABLES
/opt/local/lib/ruby/gems/1.8/gems/activerecord-2.0.991/lib/
active_record/connection_adapters/abstract_adapter.rb:151:in `log'
/opt/local/lib/ruby/gems/1.8/gems/activerecord-2.0.991/lib/
active_record/connection_adapters/mysql_adapter.rb:299:in `execute'
/opt/local/lib/ruby/gems/1.8/gems/activerecord-2.0.991/lib/
active_record/connection_adapters/mysql_adapter.rb:403:in `tables'
/opt/local/lib/ruby/gems/1.8/gems/activerecord-2.0.991/lib/
active_record/connection_adapters/abstract/schema_statements.rb:313:in
`initialize_schema_migrations_table'
/opt/local/lib/ruby/gems/1.8/gems/activerecord-2.0.991/lib/
active_record/migration.rb:388:in `initialize'
/opt/local/lib/ruby/gems/1.8/gems/activerecord-2.0.991/lib/
active_record/migration.rb:357:in `new'
/opt/local/lib/ruby/gems/1.8/gems/activerecord-2.0.991/lib/
active_record/migration.rb:357:in `up'
/opt/local/lib/ruby/gems/1.8/gems/activerecord-2.0.991/lib/
active_record/migration.rb:340:in `migrate'
/opt/local/lib/ruby/gems/1.8/gems/rails-2.0.991/lib/tasks/
databases.rake:99

I examined the connection item and it is pointing to the right DB.
It's strange since the db:migrate task work in isolation.

Anyway, for now I'll manually setup my db for test.

Thanks all,

Andrew
Posted by Andrew Selder (aselder)
on 22.05.2008 17:28
(Received via mailing list)
YEAH!!!!!!! I've got it.

I changed my rspec.rake to:

spec_prereq = File.exist?(File.join(RAILS_ROOT, 'config',
'database.yml')) ? ["db:test:purge", :testing, "db:migrate"] : :noop
task :noop do
end

task :testing => :environment do
   RAILS_ENV = ENV['RAILS_ENV'] = 'test'
   ActiveRecord::Base.establish_connection(RAILS_ENV.to_sym)
end

task :default => :spec
task :stats => "spec:statsetup"

desc "Run all specs in spec directory (excluding plugin specs)"
Spec::Rake::SpecTask.new(:spec => spec_prereq) do |t|
   t.spec_opts = ['--options', "\"#{RAILS_ROOT}/spec/spec.opts\""]
   t.spec_files = FileList['spec/**/*_spec.rb']
end

Thanks for all the assistance from everyone.

Thanks,

Andrew
Posted by David Chelimsky (Guest)
on 22.05.2008 17:35
(Received via mailing list)
On May 22, 2008, at 10:19 AM, Andrew Selder wrote:

>  RAILS_ENV = ENV['RAILS_ENV'] = 'test'
> end
>
> Thanks for all the assistance from everyone.

This is great stuff Andrew - do you have a blog? If so, please
consider blogging this.

Cheers,
David
Posted by Zach Dennis (Guest)
on 22.05.2008 18:31
(Received via mailing list)
I know the problem has been solved but you can supply global fixtures in
your spec_helper.rb file.  This avoids having to repeat them for every
describe block.

Spec::Runner.configure do |config|
  config.global_fixtures = :table_a, :table_b
end

Zach