如何使用rspec更改属性值
我是rspec的新手,我遇到了一些问题。 有人能帮帮我吗?
我有一个控制器动作负责停用用户。 我试图用rspec测试覆盖它,但结果不是我在等待的。
控制器:
def deactivate @user = User.find(params[:id]) if !@user.nil? @user.update_attribute(:active, false) redirect_to users_url end end
控制器规格
describe "PUT #deactivate" do describe "with valid parameters" do before (:each) do @user = mock_model(User, :id => 100, :login => "login", :password => "password123", :email => "email@gmail.com", :active => true) User.should_receive(:find).with("100").and_return(@user) end it "should deactivate an user" do @user.stub!(:update_attribute).with(:active, false).and_return(true) put :deactivate, :id => "100" @user.active.should eq false end end end
测试结果:
1) UsersController PUT #deactivate with valid parameters should deactivate an user Failure/Error: @user.active.should eq false expected: false got: true (compared using ==)
所以,我不明白为什么当它应该是false时,active属性仍然是真的。 有任何想法吗 ?
谢谢!
您似乎不必要地存在update_attribute方法。 尝试删除该行,看看会发生什么。
我很长一段时间都在寻找这个,无论你使用let
还是build
, update_column
总能工作
你能试试这个:
describe "should deactivate an user" do before do @user.stub!(:update_attribute).with(:active, false).and_return(true) put :deactivate, :id => "100" end it { @user.active.should eq false } end
你的期望是“错误的”。
让我们看看当你的规范it "should deactivate an user"
时会发生什么:
-
@user.stub!(:update_attribute).with(:active, false).and_return(true)
修改现有的模拟模型,因此它有一个update_attribute
,当使用参数调用时:active
和false
- 将返回
true
- 会跟踪这个电话已经发生过(这就是嘲笑所做的事情)
- (并且,与真正的
User
对象不同, 它将不执行任何其他操作 )
- 将返回
-
put :deactivate, :id => "100"
在Controller中调用真正的deactivate
- 您的Controller调用
User.find
。 但是你已经模拟了这个类方法,它将返回模拟对象@user
而不是搜索具有该id
的实际用户。 - 您的Controller调用
@user.update_attribute
。 但由于上面的步骤3,@user
here也是模拟对象。 它的update_attributes
方法是步骤1中的方法。正如我们上面所看到的,它将返回true,跟踪此调用发生的情况并且不执行任何其他操作 。 这意味着它不会改变@user
的active
属性,因此保持为true
。
调用update_attribute
时更改active
是实际User
类的对象的function,但在运行规范时没有这样的对象发挥作用。 由于此function是从ActiveRecord
inheritance的,因此您无需对其进行测试。 而只是测试模拟对象已经接收到update_attribute
: it "should deactivate an user" do @user.stub!(:update_attribute).with(:active, false).and_return(true) put :deactivate, :id => "100" @user.should have_received(:update_attribute).with(:active, false) end
(我在这里猜测旧的语法,基于它是如何使用较新的expect
语法完成的 。)
嘲笑与否?
如果您确实想要测试控制器与实际User
实现的组合function,请不要模拟User
或其对象。 而是使用请求规范从浏览器角度进行测试。 (另外,这可能是有意义的,即使你想要仅针对控制器(模拟模型)和仅模型(可能不需要双精度,除了可能用于其他模型)的隔离测试。
当你模拟对update_attribute
的调用时,模型将如何改变?
如果你是初学者:不要使用存根和嘲笑!
首先获得测试的一般知识,然后将您的知识扩展到模拟和存根。