Ruby on rails 设计、Rspec、用户期望

Ruby on rails 设计、Rspec、用户期望,ruby-on-rails,rspec,devise,Ruby On Rails,Rspec,Devise,显然,我正在使用Desive进行身份验证,我试图做的是测试是否在用户对象上调用了一个方法。因此,我的规格如下所示: it "should retrieve something for user" do @user = Factory.create(:user) sign_in @user @user.expects(:something) get :manage end 我的问题是,除非我: it "should retrieve something for user" do

显然,我正在使用Desive进行身份验证,我试图做的是测试是否在用户对象上调用了一个方法。因此,我的规格如下所示:

it "should retrieve something for user" do
  @user = Factory.create(:user) 
  sign_in @user
  @user.expects(:something)
  get :manage
end
我的问题是,除非我:

it "should retrieve something for user" do
  @user = Factory.create(:user) 
  sign_in @user
  controller.stubs(:current_user).returns @user
  @user.expects(:something)
  get :manage
end
如果sign_in@user是一个designe测试助手,那么在控制器上假装当前用户调用似乎很愚蠢。在调试器中挖掘之后,如果没有伪造当前用户,@user确实被返回,那么它也会出现,因此我不确定为什么没有达到预期


Ideas?

当前用户在存储到会话中之前被序列化;很可能,对于ActiveRecord用户模型,它存储的是用户id:

这意味着当控制器再次获取用户时:

它在会话中查找用户id,并从数据库中重新获取用户

这意味着控制器中的#current_User返回的User对象与测试中传入的@User#sign_不同,因此一个对象的存根和期望不会附加到另一个对象

我没有广泛使用Deave/Warden,但我很确定这就是发生的事情。您可以尝试在两个实例上打印出#object_id以确认这一点

挑剔的语义更新2014年2月:

在控制器上存根
#当前用户
是一种很好的方法,这取决于您对被测系统(SUT)的“边界”(即控制器)的定义。假设
#current_user
方法是由designe定义的,并由designe混合到控制器中,您可以认为
#current_user
是SUT的外部用户,因此存根是公平的

您也可以存根Desive正在访问的底层(ActiveRecord),比如存根
User.find
,以返回
@User
对象。这意味着您的规范正在测试您的操作实现以及
#current_user
的designe实现,因此如果以后更改了其中任何一项,规范都将失败


假设Deviate使用
User.find(args)
,并假设您将该方法存根,然后Deviate的更高版本更改为使用
User.where(args).first()
-您的代码没有更改,但基础库已更改,并且您的规范失败。大致考虑一下这个想法,有时您可能会喜欢这种行为(例如,考虑用stubing
Net::HTTP
方法来模拟原始HTTP响应,以便以后可以交换HTTP库),有时您不喜欢(也许这个设计问题算作一个问题).

经过昨晚的挖掘,看来你是对的!感谢您提供的信息。经过数小时的搜索,终于找到了解决方案。。非常感谢。