Тестирование переменных экземпляра контроллера с помощью Rack :: Test и Sinatra - PullRequest
8 голосов
/ 18 декабря 2009

У меня есть приложение Sinatra, которое отображает страницы только для чтения или для редактирования в зависимости от того, вошел ли пользователь в систему.

Контроллер устанавливает переменную @can_edit, которая используется представлениями, чтобы скрыть / показать ссылки редактирования. Как я могу проверить значение @can_edit в моих тестах? Я понятия не имею, как получить на текущем экземпляре контроллера под Rack :: Test.

Я использую class_eval, чтобы заглушить метод logged_in? в контроллере, но мне приходится прибегать к проверке last_response.body для моих ссылок редактирования, чтобы увидеть, установлен @can_edit или нет.

Как я могу проверить значение @can_edit напрямую?

Ответы [ 3 ]

8 голосов
/ 18 декабря 2009

К сожалению, я не думаю, что это возможно без изменения Rack :: Test. Когда вы делаете запрос во время тестирования приложения, Rack :: Test выполняет следующие действия:

  1. добавляет запрос в список последних запросов
  2. создает новый экземпляр вашего приложения и вызывает его call метод
  3. добавляет ответ вашего приложения в список последних ответов

Легко получить доступ к last_request и last_response, но, к сожалению, информация о состоянии вашего приложения не сохраняется во время его работы.

Если вы заинтересованы во взломе патча Rack :: Test для этого, начните с просмотра rack-test/lib/rack/mock_session.rb в строке 30. Именно здесь Rack :: Test запускает ваше приложение и получает стандартные значения возврата приложения Rack. (статус, заголовки, тело). Я предполагаю, что вам также придется изменить свое приложение, чтобы собрать и сделать доступными все его переменные экземпляра.

В любом случае лучше всего проверить результаты, а не детали реализации. Если вы хотите убедиться, что ссылка для редактирования не видна, проверьте наличие ссылки для редактирования по идентификатору DOM:

assert last_response.body.match(/<a href="..." id="...">/)
4 голосов
/ 27 декабря 2011

Это возможно с небольшим взломом. Экземпляры приложения Sinatra недоступны, поскольку они создаются при вызове Sinatra :: Base #. как объяснил Алекс. Этот хак готовит экземпляр вперед и позволяет следующему вызову захватить его.

require 'something/to/be/required'

class Sinatra::Base
  @@prepared = nil

  def self.onion_core
    onion = prototype
    loop do
      onion = onion.instance_variable_get('@app')
      return onion if onion.class == self || onion.nil?
    end
  end

  def self.prepare_instance
    @@prepared = onion_core
  end

  # Override
  def call(env)
    d = @@prepared || dup
    @@prepared = nil
    d.call!(env)
  end
end

describe 'An Sinatra app' do
  include Rack::Test::Methods

  def app
    Sinatra::Application
  end

  it 'prepares an app instance on ahead' do
    app_instance = app.prepare_instance    
    get '/foo'
    app_instance.instance_variable_get('@can_edit').should be_true
  end
end

Я разобрался с этой техникой, чтобы смоделировать экземпляр, который запускает текущий тест .

0 голосов
/ 25 февраля 2016

Вот противная, но жизнеспособная альтернатива

# app.rb - sets an instance variable for all routes
before do
  @foo = 'bar'
end

# spec.rb
it 'sets an instance variable via before filter' do
  my_app = MySinatraApplication
  expected_value = nil
  # define a fake route
  my_app.get '/before-filter-test' do
    # as previously stated, Sinatra app instance isn't avaiable until #call is performed
    expected_value = @foo
  end
  my_app.new.call({
    'REQUEST_METHOD' => 'GET',
    'PATH_INFO' => '/before-filter-test',
    'rack.input' => StringIO.new
  })
  expect(expected_value).to eq('bar')
end

Это позволяет вам проверять синатру перед фильтрацией и / или обращаться к переменным экземпляра, созданным для базового приложения.

...