2012-07-01 17 views
13

Chcę udostępnić metodę memoized pomiędzy moimi specyfikacjami. Więc starałem się korzystać ze wspólnego kontekstu jak tenAutomatycznie udostępniaj kontekst w RSpec

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

describe 'something' do 
    include_context :specs 
end 

To działa OK. Ale mam około 60 plików spec, więc jestem zmuszony do wyraźnego uwzględnienia kontekstu w każdym z nich. Czy istnieje sposób automatycznego uwzględnienia kontekstu współużytkowanego (lub przynajmniej definicji let) dla wszystkich grup przykładowych w spec_helper.rb?

coś takiego

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

To prawdopodobnie powiela http://stackoverflow.com/questions/9965111/rspec-shared-context-and-include-context-for-all-specs ale nadal nie ma odpowiedzi. – p0deje

Odpowiedz

28

Można skonfigurować globalne before haki używając RSpec.configure poprzez configure-class-methods i Configuration:

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

let nie jest obsługiwana w RSpec.configure, ale może uruchamiamy globalny let poprzez uwzględnienie go w numerze SharedContext module że moduł używając config.before:

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

FYI dla każdego, kto używa RSpec 3, wygląda na to, że 'RSpec :: Core :: SharedContext' zniknął i został zastąpiony przez' RSpec :: SharedContext'. – womble

+0

To jest dobre rozwiązanie. Małe wrażenie, które spotkałem w RSpec 3, polega na tym, że przekazując znacznik do włączenia i mając ten znacznik na blokach przykładowych (zamiast przykładowych bloków grupowych) otrzymałem komunikat 'NoMethodError: super: no superclass method \' foo 'for # Czy chodziło Ci o? # foo'. Poprawka ma na celu upewnienie się, że tag znajduje się w przykładowej grupie, a nie w przykładzie. –

+1

Wystąpił ten sam błąd co @GabeKopley, ale znalazłem, że uaktualnienie do RSpec 3.4.0 rozwiązało problem. – phylae

5

Można to zrobić prawie tak: istnieje mechanizm w tym moduł i włączenie moduł posiada własny mechanizm wywołania zwrotnego.

Załóżmy na przykład, że mamy udostępniony kontekst disconnected, który chcemy użyć do uruchomienia wszystkich specyfikacji modelu bez połączenia z bazą danych.

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

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

Możesz teraz utworzyć moduł, który będzie uwzględniał ten kontekst przy włączaniu.

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

Wreszcie, można włączyć ten moduł do wszystkich widowisko w normalny sposób (mam wykazała robi to tylko dla modeli, żeby pokazać, że można), który jest prawie dokładnie to, co prosiłeś.

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

który współpracuje z rspec-core 2.13.0 i 2.13.0 rspec-rails.

0

Także jeśli trzeba możliwość korzystania z danych udostępnionych w before bloków wewnątrz specyfikacje, jak ja, spróbuj podać to (jeśli jego projekt 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 

Lub spróbuj coś podobnego, spójrz na @threedaymonk odpowiedź .

1

Innym sposobem działania jest automatically share examples via metadata. Więc:

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 

Najczęstszym sposobem używam to w rspec szyn, niektóre wspólny kontekst w zależności od rodzaju przykładem grupowej. Więc jeśli masz config.infer_spec_type_from_file_location!, można po prostu zrobić:

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

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

W RSpec 3+, można to osiągnąć w następujący sposób - na podstawie odpowiedzi Jeremy Petersona.

# 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 
Powiązane problemy