Rspec在创建时吞下Postgres数据库异常

时间:2017-11-17 18:33:08

标签: ruby-on-rails rspec ruby-on-rails-5.1 ruby-on-rails-5

我无法理解Rspec(rspec 3.7,rails 5.1.4)的行为而不是抛出与数据库约束相关的异常(如预期)。

假设有人在一个关联上创建一个带有 not null 约束的表:

create_table :ce_teams do |t|
  t.string :name
  t.integer :evaluation_id, null: false

  t.timestamps
end

相应的模型是这样的:

module Ce
  class Team < ApplicationRecord
    belongs_to :evaluation
  end
end

然后在控制台中创建Team对象会引发ActiveRecord::NotNullViolation异常:

#\>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

从rspec中运行相同的

  it 'throwing not null exception if evaluation is missing in ctor' do
    expect {
      Ce::Team.create(name: 'UTEAM')
    }.to raise_exception(ActiveRecord::NotNullViolation)
  end

测试失败,一方面由于createcreate!的语义而出现,但另一方面出乎意料,因为不应该从模型验证中提出异常(这是调用create / create!)但是从数据库保存记录。

然而,使用create!将正确地抛出异常,但它是一个不同的异常(在我认为的堆栈中更高):

  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> 

发生了什么事?我的第一个直觉是在Rspec中存在一些以不同方式模拟创建(或保存)的层,省略了实际的保存。

1 个答案:

答案 0 :(得分:1)

我无法重现这个问题。这是我得到的输出

$ RAILS_ENV=development bin/rails c
Running via Spring preloader in process 24202
Loading development environment (Rails 5.1.4)
2.4.0 :001 > team = Team.create(name: 'A-Team')
   (0.3ms)  BEGIN
   (0.3ms)  ROLLBACK
 => #<Team id: nil, name: "A-Team", created_at: nil, updated_at: nil, evaluations_id: nil> 
2.4.0 :002 > team.errors.full_messages
 => ["Evaluation must exist"] 
2.4.0 :003 > team = Team.create!(name: 'A-Team')
   (0.5ms)  BEGIN
   (0.5ms)  ROLLBACK
ActiveRecord::RecordInvalid: Validation failed: Evaluation must exist
    from (irb):3

正如您所看到的,错误与createcreate!相同。尝试使用bin/rails而不是rails,我怀疑您使用的是2个不同版本的Rails。