2013-03-03 54 views
0

我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默认。

有人可以帮我吗?

谢谢...

+1

应该是验证 – apneadiving 2013-03-03 15:04:54

回答

1

我可能是错的,但是, 你的规格开始与空数据库吧?所以你的数据库中没有管理员用户。 所以,当你调用删除,你会永远拥有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 
+0

好极了,这就是它!非常感谢... – Tintin81 2013-03-03 17:03:30

1

我会做如下改变:

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 
+0

这工作同样好,甚至不需要我来改变我的规格文件。谢谢! – Tintin81 2013-03-03 17:06:13

0

另一种方法是使被调用函数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 
0

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

我已经改善一个一些问题的答案在这里的任何人都试图找出如何正确地做到这一点像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 
相关问题