2012-07-01 88 views
13

我想在我的规范之间共享memoized方法。所以我试图使用这样的共享上下文在RSpec中自动共享上下文

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

describe 'something' do 
    include_context :specs 
end 

它工作正常。但是我有大约60个spec文件,所以我不得不明确地在每个文件中包含上下文。是否有一种方法可以自动包含spec_helper.rb中所有示例组的共享上下文(或至少let定义)?

像这样的事情

RSpec.configure do |spec| 
    spec.include_context :specs 
end 
+0

这可能复制http://stackoverflow.com/questions/9965111/rspec-shared-context-and-include-context-for-all-specs但它仍然没有答案。 – p0deje

回答

28

您可以通过configure-class-methodsConfiguration设置使用RSpec.configure全球before挂钩:

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

letRSpec.configure不支持,但你可以设置一个全球let将其纳入SharedContext module并包括该模块使用config.before

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

对于使用RSpec 3的人来说,它看起来像'RSpec :: Core :: SharedContext'已经消失,并已被'RSpec :: SharedContext'取代。 – womble

+0

这是一个不错的解决方案。我在RSpec 3中遇到的一个小问题是,当传递一个标记来包含并在我的示例块(而不是示例组块)上包含该标记时,出现错误“NoMethodError:super:no superclass method \'foo'for #你的意思是? #foo'。修正只是为了确保标记位于示例组上,而不是示例中。 –

+1

我遇到了与@GabeKopley相同的错误,但是我发现升级到RSpec 3.4.0解决了这个问题。 – phylae

5

你可以做到这一点几乎是:有一个为包括模块机制,并纳入模块都有自己的回调机制。

假设例如,我们有我们想要用来运行我们所有的模型规格没有数据库连接的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和2.13.0 rspec-rails工作。

0

此外,如果您需要在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答案。

1

另一种方式去是automatically share examples via metadata。所以:

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

在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