使用 rspec 测试 before_destroy 方法

jea*_*182 4 ruby rspec ruby-on-rails

您好,我不知道如何测试这个案例场景

模型/清单.rb

before_destroy :destroyable?

def destroyable?
 raise "Error" if phase.companies.count > 0
end
Run Code Online (Sandbox Code Playgroud)

规格/模型/checklist_spec.rb

describe 'triggers' do
 describe 'destroyable?' do
  it 'should raise error if checklist phase has companies' do
    company = create(:company)
    company2 = create(:company)
    phase = create(:phase, company_ids: [company.id, company2.id])

    checklist = create(:checklist, phase: phase)

    expect(checklist.destroy).to raise_error(RuntimeError)
  end
 end
end
Run Code Online (Sandbox Code Playgroud)

我收到此错误:RuntimeError:错误

ari*_*uod 7

例外应该用于特殊情况,你的情况并不例外。对于 Rails 4,您应该返回 false,对于 Rails 5,您应该调用throw(:abort)以防止记录被破坏。

您可以添加一个错误(以获得一些反馈),然后在条件为真时中止:

before_destroy :destroyable?

def destroyable?
  return true if phase.companies.count == 0
  errors.add(:companies, 'is not empty')
  throw(:abort)
end
Run Code Online (Sandbox Code Playgroud)

现在你可以这样测试:

checklist.destroy
expect(checklist).not_to be_destroyed
expect(checklist.errors[:companies]).to eq 'is not empty'
Run Code Online (Sandbox Code Playgroud)

检查回调文档,“取消回调”部分https://api.rubyonrails.org/classes/ActiveRecord/Callbacks.html

编辑:如果您仍然希望在记录未销毁时出现异常,则 before_destroy 回调将是相同的,但您改为调用destroy!(注意“!”爆炸),这会引发异常ActiveRecord::RecordNotDestroyed

将异常作为destroy取消提出是违反直觉的,因为按照惯例它并不意味着以这种方式工作。