如何使用rspec更改属性值

时间:2012-11-12 16:21:24

标签: ruby-on-rails ruby 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属性仍为true。有什么想法吗?

谢谢!

5 个答案:

答案 0 :(得分:1)

您似乎不必要地存在update_attribute方法。尝试删除该行,看看会发生什么。

答案 1 :(得分:0)

您的期望是"错误"。

让我们看看执行规范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"调用控制器中的真实deactivate
  3. 您的控制器呼叫User.find。但是你已经嘲笑了那个类方法,它将返回模拟对象@user,而不是用id搜索实际用户。
  4. 您的控制器呼叫@user.update_attribute。但是由于上面的步骤3,@user这里也是模拟对象。其update_attributes方法是第1步中的方法。正如我们上面所见,它将返回true,跟踪此调用发生的情况,不执行任何其他操作。这意味着它将更改@user的{​​{1}}属性,以便保留active
  5. 调用true时更改active是实际update_attribute类的对象的功能,但在运行规范时没有这样的对象发挥作用。由于此功能是继承自User,因此您无需对其进行测试。而是仅测试模拟对象已收到ActiveRecord

    update_attribute

    (我在此基于how it's done with the newer expect syntax猜测旧的 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 语法。)

    要嘲笑还是不嘲笑?

    如果想要测试控制器与实际should实现的组合功能,请不要模拟User或其对象。而是使用request spec从浏览器角度进行测试。 (这可能是有意义的另外,即使你只想要控制器(模拟模型)和仅模型(可能不会需要双打,除非可能是其他型号)。

答案 2 :(得分:0)

我很长时间都在寻找这个问题,无论您使用let还是build

update_column始终都可以使用

答案 3 :(得分:-1)

你可以试试这个:

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

答案 4 :(得分:-2)

当你模仿对update_attribute的调用时,模型将如何改变?

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

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