3

我正在关注Ruby on Rails 教程,现在我需要为授权代码编写测试,例如确保用户只能编辑他们自己的配置文件。

有两个动作要测试。一是确保用户无法访问编辑其他用户个人资料的页面。这很简单,在水豚中进行了简单的“功能”测试。

但我当然也想测试 PUT 操作,这样用户就无法绕过编辑页面手动提交 PUT 请求。根据我的阅读,这应该作为 rspec“请求”测试来完成。

现在我的问题是,我必须在不同的目录中维护它们吗?(规格/功能与规格/请求)?这听起来不对,因为这两个场景密切相关。在 Rails 中通常如何进行此类测试?

例如,

describe "as wrong user" do
  let(:user) { FactoryGirl.create(:user) }
  let(:wrong_user) { FactoryGirl.create(:user, email: "wrong@example.com") }
  before { sign_in user }

  describe "visiting Users#edit page" do
    before { visit edit_user_path(wrong_user) }
    it { should_not have_selector('title', text: full_title('Edit user')) }
  end

  describe "submitting a PUT request to the Users#update action" do
    before { put user_path(wrong_user) }
    specify { response.should redirect_to(root_path) }
  end
end

第二个测试在 capybara 2.x 中不起作用,因为不再支持“put”。它必须是请求测试。现在我必须编写第二个“sign_in”方法,因为当前使用的方法仅可用于功能测试。闻起来像很多代码重复。

========我的解决方案========

在弄清楚如何登录请求测试后,感谢 Paul Fioravanti 的回答,

    before do
      post sessions_path, email: user.email, password: user.password
      cookies[:remember_token] = user.remember_token
    end

我将所有测试更改为请求测试。所以我不必将它们分成不同的文件。尽管我认为这更清洁,但保罗的解决方案也可以使用。

describe 'authorization' do
  describe 'as un-signed-in user' do
    let(:user) { FactoryGirl.create(:user) }

    describe 'getting user edit page' do
      before { get edit_user_path(user) }

      specify { response.should redirect_to(signin_path) }
    end

    describe 'putting to user update page' do
      before { put user_path(user) }

      specify { response.should redirect_to(signin_path) }
    end
  end

  describe 'as wrong user' do
    let(:user) { FactoryGirl.create(:user) }
    let(:wrong_user) { FactoryGirl.create(:user, email: 'wrong@example.com') }

    before do
      post sessions_path, email: user.email, password: user.password
      cookies[:remember_token] = user.remember_token
    end

    describe 'getting user edit page' do
      before { get edit_user_path(wrong_user) }

      specify { response.should redirect_to(root_path) }
    end

    describe 'putting to user update page' do
      before { put user_path(wrong_user) }

      specify { response.should redirect_to(root_path) }
    end
  end
end
4

2 回答 2

2

在完成 Rails 教程并将示例应用程序升级到 Capybara 2.0 后,我最终经历了拆分请求和功能规范的艰巨过程。既然您说您目前仍在做本教程,我建议您只保留 Hartl 指定的 gem(Capybara 1.1.2),完成您的示例应用程序,然后返回请求/功能问题作为重构锻炼。不过,供您参考,这就是我最终编写“错误用户”授权规范的方式:

规范/支持/实用程序.rb

def sign_in_through_ui(user)
  fill_in "Email",    with: user.email
  fill_in "Password", with: user.password
  click_button "Sign In"
end

def sign_in_request(user)
  post session_path(email: user.email, password: user.password)
  cookies[:remember_token] = user.remember_token
end

RSpec::Matchers::define :have_title do |text|
  match do |page|
    Capybara.string(page.body).has_selector?('title', text: text)
  end
end

规范/功能/authentication_pages_spec.rb

describe "Authentication on UI" do

  subject { page }
  # ...
  describe "authorization" do
    # ...
    context "as a wrong user" do
      let(:user)       { FactoryGirl.create(:user) }
      let(:wrong_user) { FactoryGirl.create(:user, email: "wrong@example.com") }

      before do
        visit root_path
        click_link "Sign In"
        sign_in_through_ui(user)
      end

      context "visiting Users#edit" do
        let(:page_title) { full_title("Edit User") }
        before { visit edit_user_path(wrong_user) }
        it { should_not have_title(page_title) }
      end
    end
  end
end

规范/请求/authentication_requests_spec.rb

describe "Authentication Requests" do

  subject { response }
  # ...
  describe "authorization" do
    # ...
    context "as a wrong user" do
      let(:user)       { FactoryGirl.create(:user) }
      let(:wrong_user) { FactoryGirl.create(:user, email: "wrong@example.com") }

      before { sign_in_request(user) }

      context "PUT Users#update" do
        before { put user_path(wrong_user) }
        it { should redirect_to(root_url) }
      end
    end

  end
end

在试图弄清楚如何将我的feature规格与我的request规格分开时,我主要使用以下两个链接作为参考:

更新:

如果您不想要自定义 RSpec 匹配器,您还可以在上面的测试中使用以下内容在title元素上获得相同的结果:

its(:source) { should have_selector('title', text: page_title) }
于 2013-02-17T05:21:45.983 回答
1

根据 Jnicklas ( https://github.com/jnicklas/capybara ),您应该将您在 spec/requests 中的所有 Capybare 规范移动到规范/功能,因为 Capybara 2.x 现在将使用规范/功能。因此,这意味着一旦您将 Capybara 规范移至功能,您就可以从规范/请求目录中完全删除这些规范。

就个人而言,我已经毫无问题地完成了 Ruby on Rails 教程。我使用 Capybara 2.x 并且从未使用过规范/功能(只是“旧”规范/请求)。对于 Rspec 2.x 支持,您必须将 require >'capybara/rspec'< 添加到您的 spec_helper.rb 文件中。没有它,您的测试可能会失败。

编辑:

我刚刚阅读了 Rspec 文档。如果您在规范中使用 Capybara,则必须将这些规范移至规范/功能。如果没有涉及 Capybara,则规范可以简单地保留在您的请求目录中。

功能规格 https://www.relishapp.com/rspec/rspec-rails/v/2-12-2/docs/feature-specs/feature-spec

请求规格 https://www.relishapp.com/rspec/rspec-rails/v/2-12-2/docs/request-specs

更多信息,来自 Rubydoc: http: //rubydoc.info/github/jnicklas/capybara/master#Using_Capybara_with_RSpec

于 2013-02-04T13:43:25.900 回答