Автоматически использовать контекст в 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
Ответы
Ответ 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.