2017-09-05 71 views
0

我正在使用FactoryGirlRspec編寫一些測試。使用Rspec在多個上下文之間傳遞變量

規格/工廠/ students.rb

FactoryGirl.define do 
    factory :student do 
    end 

    factory :student_with_profile_and_identity, class: 'Student' do 
    after(:create) do |student| 
     create(:profile, profileable: student) 
     create(:student_identity, student: student) 
    end 
    end 
end 

規格/工廠/ profiles.rb

FactoryGirl.define do 
    factory :profile do 
    birthday { Faker::Date.birthday(15, 150) } 
    sequence(:email) { |i| "profile_#{i}@email.com" } 
    first_name { Faker::Name.first_name } 
    last_name { Faker::Name.first_name } 
    password { Faker::Internet.password(6, 72, true, true) } 
    end 
end 

規格/工廠/ student_identities.rb

FactoryGirl.define do 
    factory :student_identity do 
    provider { ['facebook.com', 'google.com', 'twitter.com'].sample } 
    uid { Faker::Number.number(10) } 
    end 
end 

規格/請求/ authorizations_spec.rb

require 'rails_helper' 

RSpec.describe 'Authorizations', type: :request do 
    describe 'POST /v1/authorizations/sign_in' do 
    let!(:student) { create(:student_with_profile_and_identity) } 

    context 'when the request is valid' do 
     subject do 
     post '/v1/authorizations/sign_in', 
      params: credentials 
     end 

     context "user signs up via social network" do 
     let(:credentials) do 
      { 
      authorization: { 
       student: { 
       profile_attributes: { 
        email: student.profile.email 
       }, 
       student_identities_attributes: { 
        provider: student.student_identities[0].provider, 
        uid: student.student_identities[0].uid 
       } 
       } 
      } 
      } 
     end 

     it 'returns an authentication token' do 
      subject 
      p "1 student.profile.inspect #{student.profile.inspect}" 
      expect(json['token']).to(be_present) 
     end 
     end 

     context 'when the user has already an account' do 
     let(:credentials) do 
      { 
      authorization: { 
       email: student.profile.email, 
       password: student.profile.password 
      } 
      } 
     end 

     it 'returns an authentication token' do 
      p "2 student.profile.inspect #{student.profile.inspect}" 
      subject 
      expect(json['token']).to(be_present) 
     end 
     end 
    end 
    end 
end 

幾乎所有的測試都通過......問題是:

它創建一個新的學生在每一個方面。我期望let!(:student) { ... }是類似「singleton」,換句話說,一旦它在這裏被創建/定義let!(:student) { create(:student_with_profile_and_identity) }它將不會再被調用。

實例:在日誌是這樣的:

"1 student.profile.inspect #<Profile id: 1, email: \"[email protected]\", profileable_type: \"Student\", profileable_id: 1>" 

"2 student.profile.inspect #<Profile id: 2, email: \"[email protected]\", profileable_type: \"Student\", profileable_id: 2>" 

雖然我期望的情況下是相同的。

我錯過了什麼嗎?

回答

0

在RSpec的,let and let!是一樣的,不同之處在於let是懶惰和let!渴望:

使用let定義memoized helper方法。該值將在同一個示例中的多個調用中緩存,但不會跨越示例。

請注意,let是延遲評估的:直到第一次調用它定義的方法時纔會對它進行評估。您可以使用let!在每個示例之前強制該方法的調用。

如果你想要的東西,通過所有的例子仍然存在,你可以使用一個before hook ... before(:context)聽起來像它可能是你想要什麼。您也許能夠建立在一個before塊memoizes一個輔助方法,以避免到處使用實例變量(每this comment):

def student 
    @student ||= create(:student_with_profile_and_identity) 
end 

before(:context) do 
    student # force student creation 
end