如何使用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还是buildupdate_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"时会发生什么:

  1. @user.stub!(:update_attribute).with(:active, false).and_return(true)修改现有的模拟模型,因此它有一个update_attribute ,当使用参数调用时:activefalse
    1. 将返回true
    2. 会跟踪这个电话已经发生过(这就是嘲笑所做的事情)
    3. (并且,与真正的User对象不同, 它将不执行任何其他操作
  2. put :deactivate, :id => "100"在Controller中调用真正的deactivate
  3. 您的Controller调用User.find 。 但是你已经模拟了这个类方法,它将返回模拟对象@user而不是搜索具有该id的实际用户。
  4. 您的Controller调用@user.update_attribute 。 但由于上面的步骤3, @user here也是模拟对象。 它的update_attributes方法是步骤1中的方法。正如我们上面所看到的,它将返回true,跟踪此调用发生的情况并且不执行任何其他操作 。 这意味着它不会改变@useractive属性,因此保持为true

调用update_attribute时更改active是实际User类的对象的function,但在运行规范时没有这样的对象发挥作用。 由于此function是从ActiveRecordinheritance的,因此您无需对其进行测试。 而只是测试模拟对象已经接收到update_attributeit "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的调用时,模型将如何改变?

如果你是初学者:不要使用存根和嘲笑!

首先获得测试的一般知识,然后将您的知识扩展到模拟和存根。