如何在质量分配上进行单元测试失败? (railstutorial.org练习9.6.1)

时间:2013-08-10 02:45:37

标签: ruby-on-rails rspec

我正在阅读Michael Hartl关于RoR 4.0的教程,目前正在进行第9章的第一次练习。

我应该编写一个测试,确认无法发出PATCH请求来编辑用户的 admin 属性。为防止批量分配,本教程引入了一个仅允许某些属性的 user_params 函数。

在测试中,我正在发行

patch user_path(user), params

其中 params 是包含 admin true 值的哈希值(见下文)。在此请求之后,我希望用户的属性仍为 false

以下是问题

当测试(正确)成功使用我当前的代码时,当我将admin属性添加到 user_params 中的允许属性列表时,它也会(错误地)成功功能。

使用curl向/ users /:id发出PATCH请求会给出一个我还不太了解的错误页面。我已经尝试用PUT替换PATCH,已经阅读了某个地方,支持这种方法是相当新的,并且认为我可能没有为每个宝石提供正确的版本。我正在使用ruby 1.9.3,而本教程使用2.x。

这里有什么我想念的吗? (有关如何在rails控制台中模拟这些请求的任何提示也会有所帮助!)

我粘贴了我正在使用的代码的相关部分:

<小时/> 代码

的应用程序/控制器/ users_controller.rb


    class UsersController < ApplicationController
      before_action :signed_in_user, only: [:edit, :update, :index, :destroy]
      before_action :correct_user, only: [:edit, :update]
      before_action :admin_user, only: :destroy

      ...
        def update
            @user = User.find(params[:id])
            if @user.update_attributes(user_params)
                sign_in @user
                flash[:success] = "Profile updated"
                redirect_to @user
            else
                render 'edit'
            end
        end

      ...

        private

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

规格/特征/ users_pages_spec.rb

...
    describe "edit page" do
        let(:user) { FactoryGirl.create(:user) }
        before do
            sign_in user
            visit edit_user_path(user)
        end
...
        describe "directly patch forbidden admin attribute" do
            let(:params) do
              { user: { admin: true, password: user.password, password_confirmation: user.password } }
            end

            before { 
              patch user_path(user), params
            }
            specify {  expect(user.reload).not_to be_admin }
        end
...

app / models / user.rb

class User < ActiveRecord::Base
    before_save { email.downcase! }
    before_create :create_remember_token

    validates :name, presence: true, length: { maximum: 50 }
    VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i
    validates :email, presence: true, format: { with: VALID_EMAIL_REGEX }, uniqueness: { case_sensitive: false }
    validates :password, length: { minimum: 6 }

    has_secure_password

    def User.new_remember_token
        SecureRandom.urlsafe_base64
    end

    def User.encrypt(token)
        Digest::SHA1.hexdigest(token.to_s)
    end

    private

        def create_remember_token
            self.remember_token = User.encrypt(User.new_remember_token)
        end
end

1 个答案:

答案 0 :(得分:3)

前几天我遇到了同样的问题。如日志所示

Redirected to http://www.example.com/signin
Filter chain halted as :signed_in_user rendered or redirected
Completed 302 Found in 3ms (ActiveRecord: 0.7ms)

未将测试变为红色的原因是由于用户控制器中定义的过滤器之前的signed_in_user。因此,登录用户会修复遇到的“让测试变为红/绿”问题。

describe "forbidden attributes" do
  let(:params) do
    { user: { admin: true, password: user.password,
      password_confirmation: user.password } }
  end
  before { 
    sign_in user, no_capybara: true
    patch user_path(user), params 
  }
  specify { expect(user.reload).not_to be_admin }
end

插入sign_in后,您的测试应该是红色/绿色,具体取决于控制器中定义的强参数。

希望有助于您入门。

最佳, 本。

P.S。:但是,我没有花费太多精力调查上述提到的before_filter为何得出用户未登录的结论......