RSpec в Rails: как пропустить before_filter?

Я пытаюсь протестировать свой контроллер и разделить проблемы.

Первая проблема: кто может выполнить какое действие?
Я использую authlogic для аутентификации и be9's acl9 для авторизации. Но это не имеет значения, все мои проблемы с авторизацией решаются в before_filter. Я тестирую такой before_filter примерно так:

describe SomeModelsController, "GET to index (authorization)" do
  before(:each) do
    @siteadmin = mock_model(User)
    @siteadmin.stub!(:has_role?).with("siteadmin", nil).and_return(true)
  end

  it "should grant access to a siteadmin" do
    controller.should_receive(:current_user).at_least(:once).and_return(@siteadmin)
    get :index
    response.should be_success
  end
end

Эта спецификация работает нормально!

Теперь второй вопрос: выполняет ли действие то, что должно делать?
Это не включает проверку авторизации. Лучшим / самым чистым решением было бы пропустить все это before_filter и просто сделать что-то вроде:

describe SomeModelsController, "GET to index (functional)" do
  it "should find all Models" do
    Model.should_receive(:find).with(:all)
  end
end

Не беспокоясь о том, какой пользователь с какой ролью должен войти в систему первым. Прямо сейчас я решил это так:

describe SomeModelsController, "GET to index (functional)" do
  before(:each) do
    @siteadmin = mock_model(User)
    @siteadmin.stub!(:has_role?).with("siteadmin", nil).and_return(true)
    controller.stub!(:current_user).and_return(@siteadmin)
   end
  
  it "should find all Models" do
    Model.should_receive(:find).with(:all)
  end
end

Если бы я теперь решил, что мой siteadmin больше не имеет права доступа к действию index, это нарушило бы не только одну спецификацию, а именно спецификацию, которую ДОЛЖЕН нарушить в таком случае, но и совершенно не связанную вторую спецификацию.

Я знаю, что это в основном незначительная проблема, но было бы неплохо, если бы кто-нибудь мог придумать (элегантное) решение!


person sebastiangeiger    schedule 20.11.2009    source источник


Ответы (3)


Чтобы пропустить фильтр до:

controller.class.skip_before_filter :name_of_method_used_as_before_filter

Единственное предостережение (упомянули документы) заключается в том, что это будет только работают с фильтрами ссылки на метод, а не с процессами.

В качестве альтернативы вы можете заглушить current_user.has_role?

describe SomeModelsController, "GET to index (functional)" do
  before(:each) do
    controller.current_user.stub!(:has_role?).and_return(true)
  end

  it "should find all Models" do
    Model.should_receive(:find).with(:all)
  end
end
person Baldu    schedule 20.11.2009
comment
Спасибо, не думал об этом. Если нет возможности пропустить before_filter, это может быть лучшим решением. - person sebastiangeiger; 20.11.2009
comment
Хорошо, пропуск фильтра до работает. Единственным недостатком является то, что acl9 по умолчанию устанавливает безымянный лямбда-фильтр, поэтому мне нужно принудительно создать именованный before_filter. - person sebastiangeiger; 22.11.2009
comment
У меня это действительно не сработало (рельсы 3.2.3). Более подробную справку можно найти здесь: github.com/plataformatec/devise/wiki/ - person pixtur; 27.05.2012
comment
помните, что заглушка controller.class повлияет на все другие экземпляры этого класса во всем вашем наборе тестов. - person mkirk; 03.05.2013
comment
В настоящее время вы, вероятно, будете писать это как described_class.skip_before_action :my_callback_method - person Dennis; 26.11.2014
comment
@mkirk У нас была эта проблема в тестовом наборе производственного приложения. (Тесты случайно завершаются ошибкой, поскольку skip_before_action повлияло на тесты, выполняющиеся после теста, вызывающего skip). Это потерянные часы времени разработчика. Я бы порекомендовал вместо этого заглушку. - person Benjamin Crouzier; 26.04.2016

Старый вопрос, но мне пришлось решить его совсем недавно. Это будет работать только для Rails 3.1, для более ранних версий вы должны заменить _process_action_callbacks на filter_chain (непроверено)

Вы можете просто удалить соответствующий Proc из цепочки фильтров следующим образом (пример Test :: Unit):

class RandomControllerTest < ActionController::TestCase
  def setup
    @controller.class._process_action_callbacks.each do |f|
      @controller.class._process_action_callbacks.delete(f) if f.raw_filter.to_s.match(/**<match for your proc>**/)
    end
  end
end
person fx_    schedule 27.11.2011

Как насчет того, чтобы просто не выполнять GET-запрос? Попробуйте вызвать метод контроллера самостоятельно.

controller.index
person fernyb    schedule 24.11.2009