2017-09-05 29 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