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

On Sun, Nov 6, 2011 at 12:37, Max S. [email protected]
wrote:

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!


LOOKING FOR WORK! What: Ruby (on/off Rails), Python, other modern
languages.
Where: Northern Virginia, Washington DC (near Orange Line), and remote
work.
See: davearonson.com (main) * codosaur.us (code) * dare2xl.com
(excellence).
Specialization is for insects. (Heinlein) - Have Pun, Will Babble!
(Aronson)

Dave,

On Sun, Nov 6, 2011 at 2:25 PM, Dave A.
[email protected] wrote:

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