如何在Rails和RSpec中测试after_destroy回调?
我Ruby on Rails中这个User
类:如何在Rails和RSpec中测试after_destroy回调?
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
这个伟大的工程,并导致数据库回滚如果有人不小心删除管理员用户。
问题是,即使使用非管理员用户(由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
的管理属性设置为false默认。
有人可以帮我吗?
谢谢...
我可能是错的,但是, 你的规格开始与空数据库吧?所以你的数据库中没有管理员用户。 所以,当你调用删除,你会永远拥有User.where(“管理=?”,真).Count之间等于零
尝试测试之前创建一个用户管理
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
好极了,这就是它!非常感谢... – Tintin81 2013-03-03 17:03:30
我会做如下改变:
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
这工作同样好,甚至不需要我来改变我的规格文件。谢谢! – Tintin81 2013-03-03 17:06:13
另一种方法是使被调用函数ensure_an_admin_remains
公共职能,如check_admin_remains
。
然后您可以测试check_admin_remains
的逻辑,就好像它是任何其他函数一样。
然后在另一个测试,可以确保函数被调用的破坏,没有任何数据库的交互如下:
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
after_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
应该是验证 – apneadiving 2013-03-03 15:04:54