如何在Rails和RSpec中测试after_destroy回调



我在Ruby on Rails中有这个User类:

class User < ActiveRecord::Base
  after_destroy :ensure_an_admin_remains
  private
  def ensure_an_admin_remains
    if User.where("admin = ?", true).count.zero?
      raise "Can't delete Admin."
    end
  end
end

如果有人不小心删除了admin用户,这会导致数据库回滚。

问题在于,它似乎破坏了用户删除操作,即使在与非管理员用户(由Factory Girl生成)进行测试时也是如此。这是我的user_controller_spec.rb:

describe 'DELETE #destroy' do
  before :each do
    @user = create(:non_admin_user)
    sign_in(@user)
  end
  it "deletes the user" do
    expect{ 
      delete :destroy, id: @user
    }.to change(User, :count).by(-1)
  end
end

每当我运行这个测试,我得到这个错误:

Failure/Error: expect{
count should have been changed by -1, but was changed by 0

不应该有任何错误,但是,因为@user的admin属性被默认设置为false。

有谁能帮我一下吗?

谢谢…

我可能错了,你的规范从空数据库开始,对吗?因此,在您的数据库中没有管理员用户。当你调用delete时,你总是有User。其中("admin = ?", true)。计数等于0

试着在测试前创建一个admin用户

describe 'DELETE #destroy' do
  before :each do
    create(:admin_user)
    @user = create(:non_admin_user)
    sign_in(@user)
  end
  it "deletes the user" do
    expect{ 
      delete :destroy, id: @user
    }.to change(User, :count).by(-1)
  end
end

我将做以下更改:

before_destroy :ensure_an_admin_remains
def ensure_an_admin_remains
  if self.admin == true and User.where( :admin => true ).count.zero?
    raise "Can't delete Admin."
  end
end

另一种方法是使被调用的函数ensure_an_admin_remains成为公共函数,如check_admin_remains

你可以测试check_admin_remains的逻辑,就好像它是任何其他函数一样。

然后在另一个测试中,您可以确保在destroy时调用函数而不需要任何数据库交互,如下所示:

let(:user) { build_stubbed(:user) }
it 'is called on destroy' do
  expect(user).to receive(:check_admin_remains)
  user.run_callbacks(:destroy)
end

你不应该为控制流升高。您可以在回调期间暂停,以防止提交记录。

我已经改进了这里的一些答案,为其他人试图找出如何正确地做Rails 5

class User < ActiveRecord::Base
  before_destroy :ensure_an_admin_remains
  private def ensure_an_admin_remains
    return unless admin && User.where(admin: true).limit(2).size == 1
    errors.add(:base, "You cannot delete the last admin.")
    throw :abort
  end
end

相关内容

  • 没有找到相关文章

最新更新