I have trouble understanding the behavior of Rspec (rspec 3.7, rails 5.1.4) not throwing exceptions (as expected) related to database constraints.
Assuming one creates a table with a not null constraint on a association something like this:
create_table :ce_teams do |t|
t.string :name
t.integer :evaluation_id, null: false
t.timestamps
end
Corresponding model is this:
module Ce
class Team < ApplicationRecord
belongs_to :evaluation
end
end
Then within console creating the Team object throws an ActiveRecord::NotNullViolation
exception:
#\>RAILS_ENV=test rails c
Loading test environment (Rails 5.1.4)
2.4.2 :001 > t1 = Ce::Team.create(name: 'A-Team')
(0.2ms) BEGIN
SQL (1.2ms) INSERT INTO "ce_teams" ("name", "created_at", "updated_at") VALUES ($1, $2, $3) RETURNING "id" [["name", "A-Team"], ["created_at", "2017-11-17 18:13:17.444797"], ["updated_at", "2017-11-17 18:13:17.444797"]]
(0.2ms) ROLLBACK
ActiveRecord::NotNullViolation: PG::NotNullViolation: ERROR: null value in column "evaluation_id" violates not-null constraint
Running the same from within rspec does not:
it 'throwing not null exception if evaluation is missing in ctor' do
expect {
Ce::Team.create(name: 'UTEAM')
}.to raise_exception(ActiveRecord::NotNullViolation)
end
The test fails which is expected on one hand due to the semantics of create
vs. create!
but unexpected on the other as the exception is not supposed to be raised from the model validation (which is called on create/create!) but from the database saving the record.
However using create!
will correctly throw an exception but it is a different one (higher up in the stack i presume):
1) Ce::Team Team Model throwing not null exception if evaluation is missing in ctor
Failure/Error:
expect {
Ce::Team.create!(name: 'UTEAM')
}.to raise_exception(ActiveRecord::NotNullViolation)
expected ActiveRecord::NotNullViolation, got
#<ActiveRecord::RecordInvalid: Validation failed: Evaluation must exist>
What is going on ? My first intuition is that there exists some layer within Rspec simulating the create (or save) in a different way, omitting the actual save.