capybara / rspec:GET / PUT测试应该在不同的文件中?

时间:2013-02-04 11:39:29

标签: ruby-on-rails rspec capybara railstutorial.org

我正在关注Ruby on Rails Tutorial,现在我需要为授权代码编写测试,例如确保用户只能编辑自己的个人资料。

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

但我当然也希望测试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

2 个答案:

答案 0 :(得分:2)

在完成The Rails Tutorial并将我的Sample App升级到Capybara 2.0之后,我最终完成了分割我的请求和功能规范的艰难过程。既然你说你现在还在做教程,我建议你继续使用Hartl指定的宝石(Capybara 1.1.2),完成你的示例应用程序,然后回到请求/功能问题作为重构行使。尽管如此,这是我最后编写“错误用户”授权规范的方式:

<强>规格/支持/ utilities.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) }

答案 1 :(得分:1)

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

就个人而言,我已经完成了Ruby on Rails教程,没有任何问题。我使用Capybara 2.x并且从未使用过spec / features(只是'旧'spec / requests)。对于Rspec 2.x支持,您必须添加require&gt;'capybara / rspec'&lt;到你的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