【问题标题】:Automatically share context in RSpec在 RSpec 中自动共享上下文
【发布时间】:2015-06-26 15:14:05
【问题描述】:

我想在我的规范之间共享一个记忆方法。所以我尝试使用这样的共享上下文

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

describe 'something' do
  include_context :specs
end

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

类似的东西

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

【问题讨论】:

标签: ruby rspec


【解决方案1】:

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

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

letRSpec.configure 中不受支持,但您可以通过将其包含在 SharedContext module 中并使用 config.before 包含该模块来设置全局 let: p>

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

【讨论】:

  • 仅供使用 RSpec 3 的任何人参考,看起来 RSpec::Core::SharedContext 已经消失,并被 RSpec::SharedContext 取代。
  • 这是一个不错的解决方案。我在 RSpec 3 中遇到的一个小问题是,当传递一个要包含的标签并将该标签放在我的示例块(而不是示例组块)上时,我收到了一个错误 NoMethodError: super: no superclass method `foo' for #<RSpec::ExampleGroups::...> Did you mean? #foo。修复只是为了确保标签在示例组而不是示例上。
  • 我遇到了与@GabeKopley 相同的错误,但我发现升级到 RSpec 3.4.0 解决了问题。
【解决方案2】:

在 RSpec 3+ 中,这可以通过以下方式实现 - 基于 Jeremy Peterson 的回答。

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

  let(:admin_user) do
    create(:user, email: 'admin@example.org')
  end
end

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

【讨论】:

    【解决方案3】:

    你可以几乎那样做:有一个包含模块的机制,而模块包含有它自己的回调机制。

    例如,假设我们有一个 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。

    【讨论】:

      【解决方案4】:

      另一种方法是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】:

        另外,如果您需要在规范中使用 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 的回答。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-01-24
          • 1970-01-01
          • 2011-03-06
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多