ruby-on-railspostgresqlforeign-keysfixturesdeferrable-constraint

With Rails Minitest, how do tests pass but fail when retested?


I'm using transactional fixtures in Minitest, my tests run successfully (and pass) when I first run them:

rake test test/models/number_test.rb
Run options: --seed 31462
# Running:
..
Finished in 0.271344s, 7.3707 runs/s, 7.3707 assertions/s.
2 runs, 2 assertions, 0 failures, 0 errors, 0 skips

However, when I immediately run the again, they fail:

rake test test/models/number_test.rb
Run options: --seed 22968
# Running:
EE
Finished in 0.058652s, 34.0997 runs/s, 0.0000 assertions/s.

  1) Error:
  NumberTest#test_to_param_is_number:
  ActiveRecord::InvalidForeignKey: PG::ForeignKeyViolation: ERROR:  insert or update on table "calls" violates foreign key constraint "fk_calls_extension_id"
  DETAIL:  Key (extension_id)=(760421015) is not present in table "extensions".
  : COMMIT

  2) Error: 
  NumberTest#test_twilio's_API_is_configured_to_come_to_this_number's_URL:
  ActiveRecord::InvalidForeignKey: PG::ForeignKeyViolation: ERROR:  insert or update on table "calls" violates foreign key constraint "fk_calls_extension_id"
  DETAIL:  Key (extension_id)=(760421015) is not present in table "extensions".
  : COMMIT

2 runs, 0 assertions, 0 failures, 2 errors, 0 skips

I'm using schema_plus gem to add foreign keys to my tables.

Because fixtures are loaded in alphabetical order, I'm using the deferrable: :initially_deferred option which only does the referential integrity check at the end of the transaction so all the data is loaded to all tables before the checks. This is what's made the first run of the tests to work… however I'm not sure why it's any different for the second run.

When running the retest, shouldn't all the database tables be emptied and fixtures reloaded using the deferrable option too? It's like deferrable isn't honoured after the first time.

To get it to work, I always have to run rake db:reset between running tests which seems crazy.

Update 1: If I comment out all the fixtures for calls (which actually have nothing to do with any test in number_test.rb), all works fine… I can rerun number tests as often as I like and they still pass. So, it does seem to be something with the deferral.


Solution

  • It was a genuine referential integrity problem. numbers and calls both eventually link back to users.

    Turns out, the users fixture didn't exist on the test server. That'd do it.