Rails 3.0.7 - validates uniqueness, factory girl, and transactions with rspec

Hi,

We have a number of rspec tests that started failing with uniqueness validation failures once we added uniqueness constraints to our models despite their being no uniqueness violations at the DB level - we have unique constraints in the db and the same tests without the model-level validations work well - even negative tests that cause mysql to issue uuniqueness exceptions.

We use factory girl for creating models for tests (with create not build).

A teammate of mine determined this had to do with transactions within rspec, so for now we can work around the failing specs by turning transactions off before the tests and then on again afterwards, but this obviously has the disadvantage that if these non-transactional tests fail we have a database with test data artifacts left over in it.

We have tried moving tests set up and tear down code from before all to before each and even within each it block itself - no change.

The behavior in the tests is unique to the tests, we see no unique constraint issues in our integration nor production environments.

Anyone else here encouter this behavior and have a resolution that does not involve turning off transactions for rspec or risk losing the idempotency of tests?

If your response adds value to the thread I don't care if you top post or not :slight_smile:

Max

We have a number of rspec tests that started failing with uniqueness validation failures once we added uniqueness constraints to our models

As lazy students like to say, "post teh codez pls!" :slight_smile:

If you show us the relevant bits of the models, tests, etc., maybe we can spot something amiss.

if these non-transactional tests fail we have a database with test data artifacts left over in it.

So do like the purists say to: completely rebuild the test database from scratch for each test, which should test only one thing.

-Dave

PS: Same Max I knew at Comcast? Tell the (remaining) Tools guys I said hi!

Dave,

If you show us the relevant bits of the models, tests, etc., maybe we can spot something amiss.

Trimmed down and sanitized model used in the spec

class Widget < DnpElement

  before_save do |widget|     widget.gadgets.each do |s|       if s.locket_id != widget.locket_id         raise ActiveRecord::AssociationTypeMismatch.new( %Q{Gadget with id #{s.id} not part of locket #{widget.peergroup_id}}         )       end     end   end

  has_and_belongs_to_many \ :gadgets, \ :foreign_key => "widget_id", \ :association_foreign_key => "gadget_id",     :join_table => "widgets_gadgets"     validates :id, :name, :networkid, :uniqueness => { :message => 'must be a uniq ue value' }   validates :name, :id, :presence => true   validates :name, :length => { :maximum => 64 }

end

The spec itself just uses Factory Girl to create instances of this model - again, without transactions in rspec on the code works fine, with them on we get unique key violations. Transactions in rspec rollback the database state after each test to ensure it stays clean regardless of whether the test passed or failed, which is a good thing - without them we have to write manual clean up code.

So do like the purists say to: completely rebuild the test database from scratch for each test, which should test only one thing.

That is not a reasonable solution for us as our test database is built by importing parts of another database we pull data from - rebuilding from scratch between each test would take 1-2 minutes per test - i'd think that for most larger projects, transactional clean up is a lot more desirable than rebuild from scratch as well for the same reasons.

There is a database cleaner Gem that does what rspec now does - we used to use it before rspec had the transactional database sweetener it does now - it might record the database work done in a different way so that might be worth checking out for us, just thought I would check on the rails list for this one since this is probably the first Rails / Rspec issue we have run into as a team that we couldn't resolve ourselves :).

Looks like it might be a good solution until the issues with threading and Rspec's built in cleaner are resolved as the database_cleaner gem lets you choose a number of different strategies for cleaning.

Yeah, Dave, same Max from Comcast - and will do!

- Max

Turned out that an earlier mail thread you had responded on, Dave, had the answer - I hadn't looked into the model code deeply enough till today to realize our uniqueness constraints were missing :scope conditions to constrain them properly!

- Max