Rails RSpec测试相关模型

时间:2015-10-08 22:19:40

标签: ruby ruby-on-rails-4 patch rspec-rails model-associations

我正在做Michael Hartl Rails教程(使用Rails 4和RSpec-Rails 3.3.3)并实现具有管理员权限的用户,它通过向User模型添加admin boolean属性来实现。我决定使用一个特殊的管理模型(User has_one Admin; Admin belongs_to User),它只存储user_id;如果用户的ID存在于表中,那么它就是一个管理员(我认为考虑到管理员与非管理员的预期比例,这将是长期更有效的。)

建议用户控制器测试以确保允许的参数不允许通过Web编辑admin属性(使用Factory Girl在数据库中创建用户):

patch :update, id: user, user: { password: user[:password], password_confirmation: user[:password_confirmation], admin: '1' }

为了测试我的版本,我尝试了以下RSpec测试:

context 'attempt to assign non-admin user as admin via update request via web' do
  it 'will not update admin status' do
    session[:user_id] = user.id # user is logged in as required to make patch request
    expect { patch :update, id: user, user: { name: user.name, email: user.email, admin: { user_id: user.id } } }.to change { Admin.count }.by 0
  end
end

此测试通过,但,因为正确限制了允许的参数。要检查反向是否有效,我想测试允许用户模型中的admin params实际上是对Admin表的更改。

我更新了user_controller:

def user_params
  params.require(:user).permit(:name, :email, :password, :password_confirmation, admin: :user_id)
end

和users_controller_spec(检查管理员计数更改为1):

context 'attempt to assign non-admin user as admin via update web request' do
  it 'will not update admin status' do
    session[:user_id] = user.id
    expect { patch :update, id: user, user: { name: user.name, email: user.email, admin: { user_id: user.id } } }.to change { Admin.count }.by 1
  end
end

这给出了这个错误(文档说当分配给关联的对象的类型不正确时会引发错误):

Failure/Error: expect { patch :update, id: user, user: { name: user.name, email: user.email, admin: { user_id: user.id } } }.to change { Admin.count }.by 1
     ActiveRecord::AssociationTypeMismatch:
       Admin(#70320649341140) expected, got ActionController::Parameters(#70320662053980)

我有一种感觉,我可能完全错误的方式:管理模型应该只是直接更新而不是通过用户模型,也许通过将管理员分成这样一个单独的模型这样的恶意补丁甚至可能无法提供给用户管理员状态的请求(没有admin_controller或admin路由,因为我预计这样的分配将在数据库级别进行;只有一个简单的Admin模型,表明其与用户的belongs_to关联)。

我非常感谢有关我是否应根据自己的情况进行测试的一些建议。

提前致谢。

2 个答案:

答案 0 :(得分:0)

不过,Michael Hartl在SO上没有他自己的支持论坛和/或特定标签吗?

所以我在分支上收到错误:

1) UsersController attempt to assign non-admin user as admin via update web request will update admin status
     Failure/Error: expect { patch :update, id: user, user: { name: user.name, email: user.email, admin: { user_id: user.id } } }.to change { Admin.count }.by 1
     ActiveRecord::AssociationTypeMismatch:
       Admin(#70235772428120) expected, got ActionController::Parameters(#70235708075860)

一个通用提示只是不写控制器规格...更喜欢功能和单元测试

这是我如何解剖问题

[tansaku@Samuels-MBP-2:~/Documents/Github/MakersAcademy/Students/April2015/AndyGout/theatrebase ((ac406cd...))]$ 
→ rspec ./spec/controllers/users_controller_spec.rb:89
Run options: include {:locations=>{"./spec/controllers/users_controller_spec.rb"=>[89]}}

UsersController
  attempt to assign non-admin user as admin via update web request

[29, 38] in /Users/tansaku/Documents/Github/MakersAcademy/Students/April2015/AndyGout/theatrebase/app/controllers/users_controller.rb
   29:     @page_title = @user.name
   30:   end
   31: 
   32:   def update
   33:     require 'byebug' ; byebug
=> 34:     if @user.update_attributes(user_params)
   35:       flash[:success] = "Profile updated successfully: #{@user.name}"
   36:       redirect_to @user
   37:     else
   38:       @page_title = User.find(params[:id]).name
(byebug) @user
#<User:0x007fede0b81b60>
(byebug) user_params
{"name"=>"Andy Gout", "email"=>"andygout@example.com", "admin"=>{"user_id"=>"1"}}

我认为这里的问题似乎没有设置为通过简单的params哈希创建新的管理对象

我看到了两种方法

  1. 操纵参数以插入新的管理对象
  2. 使用accepts_nested_attributes_for http://guides.rubyonrails.org/form_helpers.html#building-complex-forms

答案 1 :(得分:0)

谢谢@SamJoseph!

我也会检查Hartl的支持(尽管我有意识地偏离他的导游......)。

这是帮助我找到解决方案的第二个建议,使用了以下更改: -

用户(用户模型):

accepts_nested_attributes_for :admin

<强> users_controller:

def user_params
  params.require(:user).permit( :name,
                                :email,
                                :password,
                                :password_confirmation,
                                admin_attributes: :user_id
                              )
end

<强> users_controller_spec:

  context 'attempt to assign non-admin user as admin via update web request' do
    it 'will update admin status' do
      session[:user_id] = user.id
      expect { patch :update, id: user, user: { name: user.name, email: user.email, admin_attributes: { user_id: user.id } } }.to change { Admin.count }.by 1
    end
  end

这通过了测试,所以我现在可以自信地工作,按照我的要求测试反向。

它很有用,因为accepts_nested_attributes_for是我很快就会再次需要的东西。

我有点不确定你在第一个建议中的意思:操纵参数插入一个新的管理对象 - 这是以某种方式在参数中添加命令直接创建一个新的管理员条目数据库(或那种效果)?我会进一步调查。

我还可以检查一下吗?不写控制器规格:鉴于这似乎是一个重要的测试,编写一个能够提供此直接补丁请求的功能规范会更好吗?你会推荐什么?

再次感谢!