Подтвердить что ты не робот

Автоматически использовать контекст в RSpec

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

RSpec.configure do |spec|
  spec.shared_context :specs do
    let(:response) { request.execute! }
  end
end

describe 'something' do
  include_context :specs
end

Он работает нормально. Но у меня около 60 файлов спецификаций, поэтому я вынужден явно включать контекст в каждый из них. Есть ли способ автоматически включать общий контекст (или, по крайней мере, let definition) для всех групп примеров в spec_helper.rb?

Что-то вроде этого

RSpec.configure do |spec|
  spec.include_context :specs
end
4b9b3361

Ответ 1

Вы можете настроить глобальные крюки before с помощью RSpec.configure через configure-class-methods и Configuration:

RSpec.configure {|c| c.before(:all) { do_stuff }}

let не поддерживается в RSpec.configure, но вы можете настроить глобальный let, включив его в SharedContext module и включая этот модуль, используя config.before:

module MyLetDeclarations
  extend RSpec::Core::SharedContext
  let(:foo) { Foo.new }
end
RSpec.configure { |c| c.include MyLetDeclarations }

Ответ 2

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

Предположим, например, что мы имеем общий контекст disconnected, который мы хотим использовать для запуска всех наших спецификаций модели без подключения к базе данных.

shared_context "disconnected"  do
  before :all do
    ActiveRecord::Base.establish_connection(adapter: :nulldb)
  end

  after :all do
    ActiveRecord::Base.establish_connection(:test)
  end
end

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

module Disconnected
  def self.included(scope)
    scope.include_context "disconnected"
  end
end

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

RSpec.configure do |config|
  config.include Disconnected, type: :model
end

Это работает с rspec-core 2.13.0 и rspec-rails 2.13.0.

Ответ 3

В RSpec 3+ это может быть достигнуто следующим образом - на основе ответа Джереми Петерсона.

# spec/supprt/users.rb
module SpecUsers
  extend RSpec::SharedContext

  let(:admin_user) do
    create(:user, email: '[email protected]')
  end
end

RSpec.configure do |config|
  config.include SpecUsers
end

Ответ 4

Еще один способ: автоматически обмениваться примерами с помощью метаданных. Итак:

shared_context 'a shared context', a: :b do
  let(:foo) { 'bar' }
end

describe 'an example group', a: :b do
  # I have access to 'foo' variable
end

Наиболее распространенный способ, которым я пользуюсь, это rspec-rails, с некоторым общим контекстом в зависимости от типа группы примеров. Поэтому, если у вас есть config.infer_spec_type_from_file_location!, вы можете просто сделать:

shared_context 'a shared context', type: :controller do
  let(:foo) { 'bar' }
end

describe SomeController do
  # I have access to 'foo' variable
end

Ответ 5

Также, если вам нужна возможность использовать общие данные в before блоках внутри спецификаций, как и я, попробуйте включить это (если это проект Rails):

module SettingsHelper
  extend ActiveSupport::Concern

  included do
    attr_reader :default_headers

    before :all do
      @default_headers = Hash[
          'HTTP_HOST' => 'test.lvh.me'
        ]
    end

    after :all do
      @default_headers = nil
    end
  end
end

RSpec.configure do |config|
  config.include SettingsHelper
end

Или попробуйте что-нибудь подобное, посмотрите на ответ @threedaymonk.