通过函数生成RSpec示例

时间:2013-08-22 20:47:03

标签: ruby-on-rails ruby rspec

我正在尝试添加一个功能,以便为未经身份验证的用户快速测试重定向。这是我到目前为止所做的:

def unauthenticated_redirects_to redirect_path #yeild
  context "when not signed in" do
    it "redirects to #{redirect_path}" do 
      yield
      expect(response).to redirect_to redirect_path
    end
  end
end


describe SomeController do
  describe 'GET #show' do 
    unauthenticated_redirects_to('/some_path') { get :show }
    context "when signed in" do
      # One thing...
      # Another thing...
    end
  end
  describe 'GET #whatever' do
    unauthenticated_redirects_to('/some_other_path') { get :whatever }
  end
end

但是,这不起作用,因为传递给describe的块无法使用主unauthenticated_redirects_to块的范围和上下文。这合理地导致错误:undefined method `get' for RSpec::Core::ExampleGroup::Nested_1::Nested_2:Class

有没有办法解决这个问题,还是有更清洁的方法来完成我应该考虑的类似事情?

4 个答案:

答案 0 :(得分:0)

答案 1 :(得分:0)

鉴于我只关注一个例子,使用shared_examples_for似乎有点矫枉过正。此外,it_behaves_like("unauthenticated redirects to", '/some_other_path', Proc.new{ get :whatever})似乎不必要地冗长。诀窍是使用#send()来维持适当的范围。

def unauthenticated_redirects_to path, method_action
  context "when not signed in" do
    it "redirects to #{path} for #{method_action}" do
      send(method_action.first[0], method_action.first[1])
      expect(response).to redirect_to path
    end
  end
end

describe 'GET #new' do
  unauthenticated_redirects_to '/path', :get => :new
end

答案 2 :(得分:0)

这是一种使用共享示例的方法,该示例基于共享元数据(在本例中为:auth => true)触发示例,并解析示例组描述以获取一些关键参数。

require 'spec_helper'

class SomeController < ApplicationController
end

describe SomeController, type: :controller do
  shared_examples_for :auth => true do 
    it "redirects when not signed in" do 
      metadata = example.metadata
      description = metadata[:example_group][:description_args][0]
      redirect_path = metadata[:failure_redirect]
      http_verb = description.split[0].downcase.to_s
      controller_method = description.match(/#(.*)$/)[1]
      send(http_verb, controller_method)
      expect(response).to redirect_to redirect_path
    end
  end

  describe 'GET #show', :auth => true, :failure_redirect => '/some_path' do 
    context "when signed in" do
      # One thing...
      # Another thing...
    end
  end

  describe 'GET #whatever', :auth => true, :failure_redirect => '/some_other_path' do
  end

end

答案 3 :(得分:0)

为了完整性,这是另一个共享示例方法,这次使用带有before调用的块参数,避免了原始范围问题:

require 'spec_helper'

class SomeController < ApplicationController
end

describe SomeController, type: :controller do
  shared_examples_for 'auth ops' do 
    it "redirects when not signed in" do 
      expect(response).to redirect_to redirect_path
    end
  end

  describe 'GET #show' do
    it_behaves_like 'auth ops' do
      let(:redirect_path) {'/some_path'}
      before {get :show}
    end
    context "when signed in" do
      # One thing...
      # Another thing...
    end
  end

  describe 'GET #new' do
    it_behaves_like 'auth ops' do
      let(:redirect_path) {'/some_other_path'}
      before {get :whatever}
    end
  end
end